Self-Host Kutt With Docker - A Modern URL Shortener

Introduction

πŸ’‘
Note: Some months ago I created a tutorial about creating an URL shortener from scratch using NestJS, MongoDB, and Docker but without any GUI. You can read my tutorial on my blog.

In this article, I will explore Kutt, a modern self-hosted URL shortener that offers a self-hosted solution for URL shortening, providing convenient analytics, authentication, and access control features.

While normally URL shorteners are considered outdated, their primary purpose today revolves around tracking clicks for marketing and analysis. Often they are seen in the bio sections of all kinds of social media pages.

What is Kutt?

Kutt is a new kind of URL shortener that can be used with custom domains and has several key features that are worth mentioning:

  • Free and open source
  • User can use their own custom domain
  • Can create custom URLs for shortened links
  • Links can be secured with a password
  • Links can contain a description
  • Links can have an expiration time
  • Statistics for every shortened URL
  • View, edit, delete, and manage your links
  • Admin accounts to moderate links (view, delete, and ban)
  • Registration and anonymous link creation can be deactivated for private use
  • Provides a RESTful API

Install Kutt

Prerequisites

Before starting to install Kut you will need to have:

  • a domain or subdomain (I use at0m.de)
  • an SMTP provider for user registration etc (I use Mailgun)

Install Kutt On Localhost With Docker Compose

Kutt can be installed locally with Docker by using the following Docker Compose file:

version: "3"

services:
  kutt:
    image: kutt/kutt
    depends_on:
      - postgres
      - redis
    command: ["./wait-for-it.sh", "postgres:5432", "--", "npm", "start"]
    ports:
      - "3000:3000"
    env_file:
      - .env
    environment:
      DB_HOST: postgres
      DB_NAME: kutt
      DB_USER: user
      DB_PASSWORD: pass
      REDIS_HOST: redis

  redis:
    image: redis:6.0-alpine
    volumes:
      - redis_data:/data

  postgres:
    image: postgres:12-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: kutt
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  redis_data:
  postgres_data:

Before starting the container download this .env file and save it as .env in the same folder as the Compose file. Adjust it to your needs, open a terminal, and execute:

docker-compose up -d

Some seconds later Kutt will be deployed on your machine and should be accessible at http://localhost:3000.

Install Kutt With Traefik On Any Domain

To quickly deploy Kutt on any domain you can use Traefik. To do this you need to have Traefik installed on the same server and your domain should point to it.

If you do not already have a Traefik Proxy installed you can check out this tutorial:

How to setup Traefik v2 with automatic Let’s Encrypt certificate resolver
Today it is really important to have SSL encrypted websites. This guide will show how easy it is to have an automatic SSL resolver built into your traefik load balancer.

If Traefik is installed on your machine create a new docker-compose.yml file and insert the following:

version: "3.8"

services:
  kutt:
    image: paulknulst/kutt
    depends_on:
      - postgres
      - redis
    command: ["./wait-for-it.sh", "postgres:5432", "--", "npm", "start"]
    networks:
      - traefik-public
      - default
    labels:
      - traefik.enable=true
      - traefik.docker.network=traefik-public
      - traefik.constraint-label=traefik-public
      - traefik.http.routers.kutt-http.rule=Host(`${KUTT_DOMAIN?Variable not set}`)
      - traefik.http.routers.kutt-http.entrypoints=http
      - traefik.http.routers.kutt-http.middlewares=https-redirect
      - traefik.http.routers.kutt-https.rule=Host(`${KUTT_DOMAIN?Variable not set}`)
      - traefik.http.routers.kutt-https.entrypoints=https
      - traefik.http.routers.kutt-https.tls=true
      - traefik.http.routers.kutt-https.tls.certresolver=le
      - traefik.http.services.kutt.loadbalancer.server.port=3000

      # Middleware www.KUTT_DOMAIN -> KUTT_DOMAIN
      - traefik.http.middlewares.redirect-www-kutt.redirectregex.regex=^https://www.${KUTT_DOMAIN?Variable not set}/(.*)
      - traefik.http.middlewares.redirect-www-kutt.redirectregex.replacement=https://${KUTT_DOMAIN?Variable not set}/$${1}
      - traefik.http.middlewares.redirect-www-kutt.redirectregex.permanent=true

      - traefik.http.routers.kutt-https.middlewares=redirect-www-kutt
  redis:
    image: redis:6.0-alpine
    volumes:
      - redis_data:/data
    networks:
      - default

  postgres:
    image: postgres:12-alpine
    env_file:
      - .env
    environment:
      POSTGRES_USER: kuttuser
      POSTGRES_PASSWORD: supersafespasswortplschangeimportant
      POSTGRES_DB: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - default

volumes:
  redis_data:
  postgres_data:

networks:
  default:
    external: false
  traefik-public:
    external: true
πŸ’‘
Note: In this Compose file I use paulknulst/kutt as my image because I personally adjusted the official Kutt image to have mail logs enabled to debug errors.

Now use the same .env file as before (download it here) and adjust it to your needs:

  • Set DEFAULT_DOMAIN to your Kutt instance
  • Adjust ADMIN_EMAILS. Set all administrator accounts
  • If you want, use RECAPTCHA_. Enter your credentials or delete it
  • Enter SMTP credentials in MAIL_
  • Set a REPORT_EMAIL where people can report malicious links

If you want to make your KUTT instance private and permit users to shorten links you have to adjust two variables in the .env file:

DISALLOW_ANONYMOUS_LINKS=true
DISALLOW_REGISTRATION=true

Before you can deploy KUTT with Traefik you have to export your Kutt domain into an environment variable:

export KUTT_DOMAIN=at0m.de

Then deploy Kutt by executing:

docker-compose up -d

If you have any error or cannot access your instance please check if you installed your Traefik as I did in my previously mentioned How To.

Kutt URL Analytics

As told before URL shorteners are mainly used for analytics purposes. In Kutt, URL analytics are pretty basic and private. Kutt will NOT track your IP or any other sensitive data!

The following image shows an example of this URL (https://at0m.de/RHPUd5) that links to a YouTube video.

Video Tutorial For Kutt

Recently, I found a very detailed installation tutorial from Awesome Open Source (btw subscribe to them) that you can watch to learn how to install Kutt:

Closing Notes

URL shorteners are cool but unfortunately, they are often used in malicious ways which are the main reason for people to avoid them. But, they can be useful for tracking clicks! Also, nowadays many services are already showing the website that is reached by following the shortened URL which makes it more trustworthy.

Another cool feature is that you can customize the links with an easy-to-type name. For example, I created https://at0m.de/donate which is a link to my buymeacoffee account but is much more rememberable than the full link.

In the end, Kutt works very well for what it is and has a fantastic minimal UI especially designed for usability.

If you're also looking for a cool and fantastic-looking URL shortener you should check it out.

You can find my public KUTT instance at https://at0m.de which I mainly use to play around with links.

Do you have any questions regarding this tutorial? I would love to hear your thoughts and answer your questions. Please share everything in the comments.

Feel free to connect with me on Medium, LinkedIn, Twitter, and GitHub.

Thank you for reading, and happy URL shortening! πŸ“‘πŸ₯³ πŸ‘¨πŸ»β€πŸ’»πŸ“‘