Skip to main content

smolu

A file-based url shortener to self-host.

About

smolu is a very simple piece of software that assume that anyone self-hosting probably already have a http server running. Thus, this software really just create a static html file for each short url.

This provide an unbeatable safety: urls are only managed by a user of the machine (assuming ssh with private key authentication), so there is no roon for SQL injection, complex authentication method, or fragile admin interface.

Features

  • Configurable short url length
  • Opt-in QR code generation
  • Self-hosted
  • No SEO bullshit, analytics, tracking, ads, payed plan
  • No database server or longrunning process (apart from whatever http server you are running)
  • No attack surface (assuming you are using a production grade http server such as nginx or caddy with TLS enabled)

Installation

  1. Install the package on your system (it is recommended that you do that as a non-root user):
pip install smolu

or

git clone https://git.sr.ht/~lattay/smolu
cd smolu
pip install .

Optionally you want to install qrencode to be able to generate QR codes.

  1. Configure the http server to serve the /srv/http/u/ directory statically (or a different root of your choice, see section Configuration) and set the Content-Type header properly (see Sample server config)

  2. Ensure the user has write permissions (obviouly you can skip that step if you intend to run smolu as root):

# we use the www-data here, but any group name will do
sudo groupadd www-data
sudo chgrp -R www-data /srv/http/u
sudo chmod -R g+w /srv/http/u
sudo usermod -aG www-data $USER

Then logout and login to apply the group change to the user.

  1. Configure the shortener (see section Configuration)

Usage

Run smolu -a <target>, it will print the short url to stdout. If enabled, the QR code will be found at <short_url>.png

Note: this is designed for individual user, meaning it is not designed for millions of urls, or for super fast generation. It will check for collisions though (in a parallel unsafe way though, again a single user won't have a problem). The default is to use 4 bytes of timestamp and 2 random bytes, however even 2+1 should be just fine for personal use. The bytes are base64 encoded so for each 3 bytes of the id, you get 4 characters in the url.

Configuration

The configuration is done with smolu -c.

$ smolu -c
Configure wizard:
URL prefix?
Default: example.com/u/
> mydom.io/u/
Server root?
Default: /srv/http/u
>
Random byte length?
Default: 2
> 1
Timestamp byte length?
Default: 4
> 2
Generate QR code?
Default: no
> yes
Current configuration:
{
    "server_address_prefix": "mydom.io/u/",
    "server_root": "/srv/http/u",
    "template": "\n<!DOCTYPE HTML>\n<html lang=\"en-US\">\n    <head>\n        <meta charset=\"UTF-8\">\n        <meta http-equiv=\"refresh\" content=\"0; url={url}\">\n    </head>\n    <body>\n        If you are not redirected automatically, follow this <a href='{url}'>link</a>.\n    </body>\n</html>\n",
    "random_byte_length": 1,
    "timestamp_byte_length": 2,
    "gen_qr": true
}

You can also change one field at a time with smolu -c <field>=<value>. When omiting the value, smolu -c <field>, the value is read from stdin.

$ smolu -c template <<EOF
<!DOCTYPE HTML>
<html lang="en-US">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="refresh" content="0; url={url}">
    </head>
    <body><a href='{url}'>link</a>.</body>
</html>
EOF

The configuration file is located at ~/.config/smolu/config.json

Note: Currently the only field supported by the template is {url}. This is a python .format style template, so if you need literal { or } you need to double then.

Sample server config

As mentioned before, smolu only creates file, but you are responsible for serving them. What the server must do is:

  • serve static files found in /srv/http/u/ or whatever root you have configured
  • set the Content-Type header of the generated files to text/html; charset=utf-8 (because they have no extension)
  • set the Content-Type header of the /u/*.png files to image/png (that's usually automatic, but you need to make sure the other action does not override the normal behaviour)

Here are some examples of achieving that with two of the very best open-source http servers out there.

Caddy

doc for the Caddyfile:

example.com:443 {
	root * /srv/http
	@html {
		path /u/*
		not path *.png
	}
	header @html Content-Type "text/html; charset=utf-8"
	file_server
}

Nginx

doc for the static file part:

server {
    listen 443 ssl;
    server_name example.com;

    root /srv/http;

    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    location ~ ^/u/.*\.png$ {
        # nothing special
    }

    location /u/ {
        add_header Content-Type "text/html; charset=utf-8";
    }
}

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

Metadata

Release files for smolu 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for smolu 0.4.0
File Size Uploaded Provenance Actions
smolu-0.4.0.tar.gz 9.9 kB Without provenance Details for smolu-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for smolu 0.4.0
File Interpreter ABI Platform Actions
smolu-0.4.0-py3-none-any.whl Python 3 none any Details for smolu-0.4.0-py3-none-any.whl

Total release size: 18.9 kB

Release files / smolu-0.4.0.tar.gz

Download URL smolu-0.4.0.tar.gz
Size 9.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a1f931b33ceaa319cda9d28837aedab7b5c54fa7c50899d78881a795dad1ba13
BLAKE2b-256 checksum
How to use checksums
5317d63b4bef3051919217d2b99de291534243d70752b5b3e0ac8b76dac9f65c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.13

Release files / smolu-0.4.0-py3-none-any.whl

Download URL smolu-0.4.0-py3-none-any.whl
Size 9.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6de0290d5324a7f7aeb3b7f57d9c503fcbb9d8effc8975ecee7bcbe375de7a97
BLAKE2b-256 checksum
How to use checksums
6ec6602a0362b92eb7c189beb273ad771b03605bef3272f83f71bc2a3c091037
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.13

Security for smolu 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page