Self-Host Shlink: Your Own URL Shortener (Ditch Bitly for Good)

Self-Host Shlink: Your Own URL Shortener (Ditch Bitly for Good)

I got tired of Bitly tracking my clicks and charging for features I could run myself. Here's how I set up Shlink in Docker — a self-hosted URL shortener that's fast, private, and actually better.

💡 Disclosure: This article contains affiliate links. If you make a purchase through these links, we may earn a small commission at no extra cost to you. This helps support the site and keeps the content free.

I’ve been self-hosting most of my stack for years. Email? Mailcow. Password manager? Vaultwarden. File sync? Syncthing.

But one thing I kept outsourcing was URL shortening. Every link I shared went through Bitly or some other service. It felt harmless — who cares about link shortening, right?

Turns out, I should have cared more.

A few months ago I noticed Bitly was tracking every click across all my shared links. My newsletter links, my project docs, even personal links to friends. They knew where people clicked, what devices they used, which countries they were in. And I was paying them for the privilege of handing them my data.

That’s when I started looking for alternatives.

Why Not Just Use Bitly for Free?

Let me be honest: Bitly’s free tier works. And if you only shorten a link once a month, maybe you don’t need to self-host this.

But here’s the thing I realized — URL shorteners sit in a weird spot. They’re so simple that you don’t think about them. But they’re also a privacy nightmare when you do:

  • Bitly tracks everything — every click, every referrer, every device. That data lives on their servers forever.
  • They can change the terms — remember when they killed the free tier for API access? Anyone who built on their API got burned.
  • The links aren’t really yours — if Bitly shuts down, every link you’ve ever shortened dies with them.

And honestly? The “paid” features are things you’d expect for free. Custom domains? Paid. QR codes? Paid. Analytics export? Paid.

I’d rather run this myself and own the data.

Shlink is an open-source URL shortener you can run on your own server. It’s written in PHP, has a clean API, and comes with a proper dashboard. There’s also a mobile app (Shlink) that you can connect to your instance.

What sold me:

  • Custom domains — run short links on your own domain (like s.yourdomain.com)
  • Real analytics — visits, referrers, browsers, locations. All stored on your server.
  • Tags — organize links by project or campaign
  • QR codes built-in — generate them from the API or dashboard
  • API-first — you can integrate it with anything
  • No tracking bullshit — the data is yours, end of story

I’ve been running it for about six months now and it’s been rock solid. Zero maintenance, zero issues.

How to Set It Up

You need Docker and a domain where Shlink can live. I’m putting it behind my Traefik reverse proxy (if you’re using Nginx Proxy Manager, same idea).

Step 1: Docker Compose

Create a directory and a compose file:

mkdir -p ~/shlink
cd ~/shlink
# docker-compose.yml
version: "3.8"

services:
  shlink:
    image: shlinkio/shlink:stable
    container_name: shlink
    restart: unless-stopped
    environment:
      - DEFAULT_DOMAIN=s.yourdomain.com
      - IS_HTTPS_ENABLED=true
      - DB_DRIVER=postgres
      - DB_HOST=shlink-db
      - DB_PORT=5432
      - DB_NAME=shlink
      - DB_USER=shlink
      - DB_PASSWORD=change_this_to_something_secure
    ports:
      - "8080:8080"
    depends_on:
      - shlink-db
    volumes:
      - ./data:/etc/shlink/data

  shlink-db:
    image: postgres:16-alpine
    container_name: shlink-db
    restart: unless-stopped
    environment:
      - POSTGRES_USER=shlink
      - POSTGRES_PASSWORD=change_this_to_something_secure
      - POSTGRES_DB=shlink
    volumes:
      - ./db-data:/var/lib/postgresql/data

If you want the web dashboard too, add this:

  shlink-web-client:
    image: shlinkio/shlink-web-client
    container_name: shlink-web
    restart: unless-stopped
    ports:
      - "8081:8080"
    environment:
      - SHLINK_SERVER_URL=https://s.yourdomain.com

Fire it up:

docker compose up -d

Check the logs:

docker logs shlink

If you see something like “Server started” — you’re good.

Step 2: Configure Your Reverse Proxy

I use Traefik, but here’s the general idea:

  • Point a subdomain like s.yourdomain.com to your server
  • Route traffic to the Shlink container on port 8080
  • Enable HTTPS (Let’s Encrypt)

If you’re using Nginx Proxy Manager, add a proxy host pointing to http://shlink:8080 and enable SSL.

Once it’s running, open https://s.yourdomain.com and create an API key. Then you can use the web client (if you added it) or just curl:

curl -X POST https://s.yourdomain.com/rest/v2/short-urls \
  -H "X-Api-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"longUrl": "https://selfhostable.dev/blog/self-host-shlink-url-shortener-guide"}'

You’ll get back something like https://s.yourdomain.com/abc123.

That’s it. One API call and you’re shortening links like a pro.

The real power is when Shlink becomes part of your automation. Here are a few ways I use it:

N8N automation — I have a workflow that auto-generates short links whenever I publish a new blog post. It hits the Shlink API, tags the link with “blog”, and saves the result to a table.

Newsletter — When I send out emails, every link goes through Shlink. I can see which articles people actually click on, without giving Mailchimp or Buttondown access to my analytics.

CLI shortcuts — I made a bash function that shortens URLs from the terminal:

function shorten() {
  curl -s -X POST https://s.yourdomain.com/rest/v2/short-urls \
    -H "X-Api-Key: $SHLINK_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"longUrl\": \"$1\"}" | jq -r '.shortUrl'
}

Now I can just type shorten https://github.com/some-long-url and get a short link back. Super handy for sharing stuff in Discord or Slack.

What About Security?

Since Shlink is exposed to the internet (people need to follow your links!), there are a few things to think about:

  • Use a separate subdomain — don’t run it on your main blog domain. Keep it isolated.
  • Enable HTTPS — obvious but worth saying. Let’s Encrypt makes this free.
  • Put it behind a VPN — if it’s just for personal use, don’t expose the dashboard to the internet at all. Only make the redirect endpoint public.

🚀NordVPN

Running a self-hosted URL shortener? Keep your infrastructure secure with a trusted VPN.

Get NordVPN →

Affiliate link — we may earn a commission at no extra cost to you.

I route all my admin traffic through NordVPN when managing Shlink’s dashboard. It adds an extra layer between my management interface and the internet, and honestly, it’s cheap insurance.

What I’d Do Differently

A couple of things I learned the hard way:

  1. Set up a proper domain early — I started with shlink.myserver.com which was fine, but then I migrated to a shorter domain for better-looking links. If you can get a short domain (like s.ly or similar), do it from the start. Changing domains later means all your old links break.

  2. Don’t go crazy with tags — I created like 50 tags in the first week. Then I never used most of them. Keep it simple: blog, project, personal, and maybe one or two custom ones.

  3. Back up the database — this is a small app but losing your links is annoying. Just add the db-data directory to whatever backup routine you already have. I use Restic (check the backup guide on this site).

  4. Monitor the disk — Shlink stores analytics data. If you get heavy traffic, the database can grow. It’s not massive, but worth keeping an eye on if you’re running on a small VPS.

🚀NordVPN

Keep your self-hosted services secure with a reliable VPN solution.

Get NordVPN →

Affiliate link — we may earn a commission at no extra cost to you.

Is It Worth It?

If you only shorten one link per month, probably not. Just use whatever free service you like.

But if you’re sharing links regularly — for a blog, newsletter, project docs, or even just in your communities — owning your shortener is one of those quality-of-life improvements that adds up over time.

The links are yours. The data is yours. And you never have to worry about a VC-backed startup deciding your free tier isn’t profitable enough.

I switched six months ago and I genuinely can’t remember the last time I used Bitly. The API is better, the privacy is better, and honestly, self-hosting it feels like taking back a tiny piece of the web that I’d outsourced without thinking.

You should try it. Set it up this weekend. It takes ten minutes, and you’ll wonder why you didn’t do it sooner.


Running on a Hetzner CX21, behind Traefik, backed up with Restic. Written from experience — I broke my first Shlink install by forgetting to set the default domain.

Stay in the loop 📬

Get self-hosting tutorials, tool reviews, and infrastructure tips delivered to your inbox. No spam, unsubscribe anytime.

Join 0 self-hosters. Free forever.