flatlink. Short links you own.
A short-link service with a QR generator that you run yourself. Plain PHP – no database server, no Composer, no build step. Copy it, configure it, done.
View on GitHub Get started Deutsch
Why open?
“We don’t track you” is just a claim without the source
Any short-link service can claim it doesn’t track its visitors. The claim only becomes verifiable once the source code sits next to it. This is everything flatlink stores about a short link:
No record of individual visits – hence no IP addresses, no times of day, no stored user agents. The lower three lines are totals: three coarse attributes are taken from each request and added up immediately, and of the referrer only the hostname survives (never the path, which can carry a search query). That answers “where do my clicks come from” without holding on to a single visit – and if even that is too much, one line of configuration turns it off.
The redirect path doesn’t even start a session unless the link is password-protected. Checking is explicitly invited – that is what the open source is for: the entire counting logic lives in inc/store.php.
A look inside
What it feels like
The screenshots show the German interface; the instance language can be set to English.
Measured
Fifty million links cost three percent
A file instead of a database server sounds like a limit. Measured against fifty million short links (a 13 GB file), throughout with the 128 MB memory limit typical of shared hosting:
| Operation | 2 links | 50 M links |
|---|---|---|
| Redirect, counted | 0.208 ms | 0.214 ms |
| First page of the admin list | – | 0.04 ms |
| Last page (page 1,000,000) | – | 0.74 ms |
| One pass over every link | – | 50 s at 2 MB |
A short link is found by its primary key – whether two or fifty million others sit next to it changes nothing. Anything that grows with the data is streamed rather than loaded: cleanup, search and export go row by row at constant memory.
Honestly alongside: writes happen one after another, not in parallel – SQLite takes one writer. And on shared hosting the ceiling is eventually your contract’s inode quota, not the database. Both are spelled out with numbers in the README.
What you get
A complete service, not a code snippet
QR codes without third-party code
Its own encoder per ISO/IEC 18004. Shapes, colours, a logo in the middle, a frame with free text – as SVG, PNG and print-ready PDF.
Printed, and still changeable
You can’t recall a printed code – but you can change where it points. Every change is recorded, the last twenty per link.
One code, several targets
Link-in-bio pages with their own styling, plus switches by language or device and time windows per link.
Browser extension
Shorten the page you’re on with one click – against your own instance, for Chrome and Firefox.
Wi-Fi, contact, event
Static QR codes whose content sits inside the code itself: they keep working even if the instance is gone.
For organisations
Sign-in against an existing directory (LDAP, Active Directory) or via the web server (Shibboleth, SAML, OIDC).
Order once you pass a hundred links
Tags, work groups with their own permissions and limits, namespaces per department, bulk CSV import.
Several domains
One flatlink server runs any number of addresses, each with its own namespace: client-a.link/shop and client-b.link/shop are two different short links. Clients bring their own domain without having to coordinate codes.
Passkeys instead of codes
Two-step sign-in: a passkey replaces the password, a one-time code adds to it.
API and moving in
A REST API with an OpenAPI description and scoped keys. Exports from Bitly, YOURLS, Shlink and Kutt can be imported as they are.
No database to set up
Links and accounts live in one SQLite file. No server for anyone to set up and maintain, no migration steps on update – and a backup is a file copy.
Abuse protection
Rate limits, a report form, blocking and optionally Google Safe Browsing – including a re-check pass over existing links.
Access and erasure
Every account downloads its data as JSON and deletes itself – without asking the operator.
Sessions and audit log
Sign out individual devices; administrative actions stay traceable – and visitors never appear in that log.
Accessible and bilingual
Interface in German or English, a WCAG 2.1 AA self-assessment and a template declaration for public bodies.
Who it’s for
People who’d rather run it themselves
Clubs, surgeries, restaurants
Print a QR code and change its target later without replacing the sticker. That is what a short link on paper is for.
Libraries, schools, public bodies
Short links that must not leave the building. Sign-in via your existing directory, groups per department, your own namespaces.
Agencies
Several brands under one roof: a domain per client, shared work groups, an API for automation.
Two instances run in public: 1337.kiwi as a free service and hfmt.art at the Hamburg University of Music and Drama, whose requirements shaped a good deal of what flatlink does – directory sign-in, groups, namespaces, the CSV import from YOURLS.
Installation
Copy, configure, done
No Composer, no build step, no database server. All you need is PHP 8.1 (with pdo_sqlite, which is practically always there) and a web server that can rewrite paths.
If you prefer containers: a Dockerfile and a compose file are in the repository, plus a Kubernetes manifest. The container runs rootless and with any user ID.
For serious operation there is a thorough deployment guide – from file permissions through mail delivery to a complete Shibboleth setup – and a customisation guide for your own colours and logos.
Licence
Free to use, with two conditions
flatlink is licensed under the GNU AGPL v3 with an additional attribution term under § 7(b) of the licence. Use it, run it, change it, redistribute it, rename it, recolour it – all allowed, commercially too, without asking. Two things stay:
The attribution line stays
Every interface names “flatlink” and links to this project. Translate it, reword it, set it small and quiet – all fine. Hiding it is not.
Changes stay open
Anyone offering a modified version as a service makes its source available to their users. Running it unmodified publishes nothing.
Why not MIT: because MIT allows closing the source and building a service from it where nobody can check what happens to the click data. Being able to check exactly that is the point of this project.
For a version without the attribution line – as a white label, say – a written waiver is available. A short email is enough.
Contributing
Bug reports and pull requests are welcome – with one request up front: being dependency-free is not an accident, it is the core of the project. A patch that requires Composer, a build step or a database server will not be merged, however much more elegant it would be.
Please don’t report security issues publicly – use the route described in SECURITY.en.md.