What good is a URL shortener if it’s not shortening URLs? None, I say. NONE!


Installing chr is as easy as following these simple steps:

  • Clone the latest repo: git clone (then cd chr)
  • Install the package: python install
  • Copy and modify the example script: cp && $EDITOR
  • Run chrso: gunicorn -b -p /tmp/ mychr:app

Want to configure your instance (hint: you probably do)? has all the essentials.

Running multiple instances

Assuming you’re using something like gunicorn (as suggested), you can simply specify a different pid file, and that will handle itself.

If you want to isolate the databases (let’s be honest, you probably do), you’ll have to specifically set chrso.redis_namespace to something specific to each.

Keep this in mind if you ever want to hit up the database to remove or modify URLs, also.

# In (`gunicorn ... chr1:app`)
import chrso
chrso.redis_namespace = "chr1"
from chrso.main import app

# In (`gunicorn ... chr2:app`)
import chrso
chrso.redis_namespace = "chr2"
from chrso.main import app


When users submit a URL to be shortened, they’re pushed against a rough URL-like regex provided by WTForms.

There’s no baked in checks for legitimate domains, 200 OK replies or anything like that [open an issue on the repo if you’re interested and I’ll work on it].


Logging is not implemented as of the 3.x branch anymore - but there’s not much that can happen, so don’t fret. (Gunicorn probably provides it, not 100%)


At the current time of writing [v3.0.8], there is currently no way to moderate the shortened URLs built into chr.

If you’re serious about removing links, or you need to remove a link which has been reported to you, you’ll have to use redis-cli.

Say we want to remove because it’s scum:

$ redis-cli
# Pull the row id
redis> hget chr:id_map foo
# Ensure it's the URL we're expecting
redis> get chr:url:1:long
# Remove it from the id_map
redis> hdel chr:id_map 1
(integer) 1
redis> exit

Simply removing a URL from the id_map will mean it’s not accessible for users, but you will still have the long/short url, related info (IP, useragent) about the submitter, etc.

Clean deployment

If you want to deploy chr somewhere in production (which you.. would if you’re reading this) you’ll want to look at one of the standard deployment options for Flask.

It’s also a nice idea to bind to a unix socket rather than a port. Just tidier:

gunicorn -b unix:/tmp/chr.sock -p /tmp/ example:app


upstream chrso {
    server unix:/tmp/chr.sock;

server {

    location / {
        proxy_pass http://chrso;

    # Let nginx serve static files
    location /static/ {
        # Wherever you installed `chrso`
        root /path/to/chrso;



Project Versions

Table Of Contents

Previous topic

Welcome to chr’s documentation!

Next topic

Automated Documentation

This Page