liblin
libl.in (libre link) is a URL shortner built for hackers by a hacker. If you have a Codeberg account, you are already a libl.in user.
liblin is a free software, released under GPLV3 or later, and it’ll remain library forever. It stores know none of your data, yet it adds as your URL shortner. However in the future, for performance reasons, we could be storing your short links for a period of time.
The Idea
Most URL shorteners keep a database that maps a short code to a destination. liblin flips that around: your git repository is the database.
A liblin link has the shape:
https://libl.in/<username>/<document>
With the default libl.in mapping, <username> is a Codeberg account and
<document> is a text file on the main branch of that account’s liblin
repository. liblin fetches that file and redirects the visitor to the URL on
its first line. The rest of the file is ignored, so it can hold notes.
For example, Alice creates demo.txt in her liblin repository with this
first line:
https://example.com/a/very/long/url
Then https://libl.in/alice/demo redirects to that URL. The filename without
the .txt suffix becomes the last part of the short link. If Alice later edits
and commits demo.txt, the short URL stays the same and points to the new
destination.
How a request flows
sequenceDiagram
autonumber
actor V as Visitor
participant L as liblin
participant R as domain-slurps.edn
participant G as Git host
participant D as Destination
V->>L: GET https://libl.in/alice/demo
L->>L: domain = libl.in:80<br/>paths = ["alice", "demo"]
L->>R: look up libl.in:80
R-->>L: URL template
L->>L: render template
L->>G: GET /alice/liblin/raw/branch/main/demo.txt
G-->>L: first line = destination URL
L-->>V: 302 Found<br/>Location: destination URL
V->>D: follow redirect
D-->>V: destination page
- Receive the short URL. The browser requests
/alice/demofromlibl.in. - Find the domain mapping. liblin reads the RDL file named by
LIBLIN_DOMAINSand looks up the host and port,libl.in:80. The path segments becomepaths, here["alice", "demo"]. - Render the file location. The RDL template turns those segments into
the raw URL of a file on the git host. In the default mapping, the first
segment selects the repository owner and the remaining segments form the
file path inside the repository. So
alice/demomeansdemo.txtin Alice’sliblinrepository, andalice/docs/demomeansdocs/demo.txt. With no document segment,index-if-emptyfalls back toindex.txt. - Fetch the file. liblin downloads that text file from the git host.
- Read the first line. That line is the real destination; later lines are ignored.
- Redirect. liblin returns
302 Foundwith the destination in theLocationheader. The browser follows it.
liblin reads both the RDL file and the destination file on every request, so without a caching proxy a commit is visible on the next request. liblin itself keeps no link cache. A future version of liblin may cache links briefly for performance, but the repository would remain the source of truth. If you put Nginx in front of liblin, see Hosting for optional cache settings and their trade-offs.
Why git?
Using a repository as the link store has several advantages:
- No account or dashboard. Your existing Codeberg account and repository are all you need.
- Versioned by default. Every link change is a commit, so you can inspect, revert, and audit it.
- Editable anywhere. Use the Codeberg web editor, git, or any tool that can write a text file.
- Portable. The redirects are plain text in a repository you control; you can fork, back up, or move them.
- Stateless server. liblin can restart or be replaced without migrating a database.
Because the destination lives in your repository, a short link is only as private as that repository. On the hosted service the file must be publicly readable, since liblin fetches it without your credentials. Do not put secrets in a destination URL.
One server, many domains
RDL is what connects a hostname to a repository layout. The hosted service uses an entry like this:
{"libl.in:80"
"https://codeberg.org/{{ paths[0] }}/liblin/raw/branch/main/{{ paths | rest | join | index-if-empty }}.txt"}
Change the template to support a different git host, repository name, branch, or file layout. See Redirect Language for the template language and Hosting for running your own instance.
Ready to create a link? See Getting Started.