---
title: "Deploy Shlink — Self-Hosted URL Shortener & Bitly Alternative"
description: "Self-host Shlink — branded short links, analytics & REST API"
category: "Other"
url: https://railway.com/deploy/shlink-url-shortener
---

# Deploy Shlink — Self-Hosted URL Shortener & Bitly Alternative

Self-host Shlink — branded short links, analytics & REST API

**[Deploy Shlink — Self-Hosted URL Shortener & Bitly Alternative on Railway](https://railway.com/template/shlink-url-shortener)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/shlink-url-shortener/manifest.json

- **Creator:** SilverBanana
- **Category:** Other

## Template content

### Postgres https://devicons.railway.app/i/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### Shlink Web Client https://raw.githubusercontent.com/shlinkio/shlink.io/main/public/favicon.png

- **Source:** MykalMachon/shlink-on-railway
- **Public domain:** Yes

### Shlink

- **Image:** shlinkio/shlink:stable

## Documentation

# Deploy and Host Shlink on Railway

Shlink is a powerful open-source URL shortener with a REST API, detailed click analytics, QR codes, and custom short domains — a self-hosted alternative to Bitly that you fully own. Create branded short links, track every visit with geolocation and device data, and manage everything through the API, CLI, or web client, with no per-link fees or data sold to anyone. This template deploys Shlink with PostgreSQL and an initial API key, wired for a custom short domain — so you own both your links and the analytics behind them, in minutes.

---

## What This Template Deploys

| Service | Purpose |
| --- | --- |
| **Shlink** | The URL shortener API, redirect engine, and analytics on port `8080` |
| **PostgreSQL** | Short URLs, visit records, tags, and API keys |

Both connect over Railway's private network. Shlink handles redirects and the REST API, PostgreSQL stores your links and every visit, and an initial API key is created on first boot so you can start creating short URLs immediately.

---

## About Hosting

Shlink is straightforward to run, and a couple of specifics make it a real shortener rather than a toy — this template handles them.

**Your short domain is the whole point — set `DEFAULT_DOMAIN`.** A URL shortener is only useful if the links are short and branded, so `DEFAULT_DOMAIN` should be a custom short domain (like `s.yourbrand.com`) that you add to your Railway service and point at it with DNS. If you leave it as the long `*.up.railway.app` subdomain, your "short" links won't actually be short. Set your short domain and add it in Railway's settings — this is the difference between a branded shortener and an unusable one.

**An admin API key is created on first boot.** `INITIAL_API_KEY` generates an admin key at container startup, which you use to authenticate the REST API, the CLI, and the web client. Set it to a strong value and keep it secret — it can create and manage every short URL on your instance.

**PostgreSQL, not SQLite — this matters for production.** Shlink's own documentation is explicit that SQLite is for testing only and risks breakage when updating Shlink. This template uses PostgreSQL, which Shlink recommends for production due to its performance with indexes and concurrent redirects, so your instance stays reliable as your link volume and traffic grow.

**The web client is separate — point it at your API.** Shlink's server is headless (API and redirects only); the visual dashboard is a separate shlink-web-client app. You can deploy it separately or use the hosted client at app.shlink.io, pointing it at your Railway API URL with your API key — or drive everything through the REST API and CLI directly.

**Analytics and QR codes are built in.** Every short URL tracks visits with referrer, device, and — with an optional GeoLite2 license key — geolocation, and each link has a QR code generated automatically. `IS_HTTPS_ENABLED=true` is set for Railway's automatic HTTPS, and `REDIRECT_STATUS_CODE` controls whether redirects are cached (301) or always counted fresh (302). Your short URLs, visit records, tags, and API keys all persist in PostgreSQL — the single component to back up.

Typical cost: **~$5/month** on Railway for Shlink and PostgreSQL — it's lightweight, scaling with redirect traffic. Shlink is MIT-licensed and free, versus Bitly's per-link and analytics pricing.

---

## How It Compares

| | Shlink (self-hosted) | Bitly | Dub | TinyURL |
| --- | --- | --- | --- | --- |
| Custom short domain | Yes | Paid | Yes | Paid |
| Analytics | Full, self-owned | Tiered | Yes | Limited |
| REST API | Full | Paid tiers | Yes | Limited |
| QR codes | Built-in | Paid | Yes | Some |
| Data ownership | Full — your infra | Vendor | Vendor | Vendor |
| Self-hostable | Yes | No | Partial | No |

Bitly is polished but gates custom domains, API access, and analytics behind paid tiers and holds your click data. Dub is a strong modern option but vendor-hosted. TinyURL is simple but limited and not self-hosted. Shlink's edge is a full-featured shortener — custom domains, complete analytics, a REST API, and QR codes — self-hosted at flat cost, with your links and every click's data on infrastructure you own.

---

## Deploy in Under 5 Minutes

1. Click **Deploy on Railway** — Shlink and PostgreSQL build and wire together (~3 minutes)
2. Set `DEFAULT_DOMAIN` to your custom short domain and add that domain in Railway's settings
3. Set a strong `INITIAL_API_KEY` and confirm the database is connected
4. Point DNS for your short domain at Railway, so links resolve over HTTPS
5. Create short URLs via the web client, the REST API, or the CLI using your API key

Use the hosted web client at app.shlink.io pointed at your API, or call the REST API directly.

---

## Common Use Cases

- **Branded short links** — share `s.yourbrand.com/xyz` links you own instead of a generic shortener
- **Campaign tracking** — track clicks with geolocation, device, and referrer data per link
- **QR code campaigns** — generate QR codes for print and events, with click analytics behind them
- **Data-owned link management** — keep your links and click data on your own infrastructure

---

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `DEFAULT_DOMAIN` | Required | Your custom short domain (e.g. `s.yourbrand.com`) |
| `INITIAL_API_KEY` | Required | Admin API key created on first boot — set a strong value |
| `IS_HTTPS_ENABLED` | Pre-set | `true` for Railway's automatic HTTPS |
| `DB_DRIVER` / `DB_*` | Auto-injected | PostgreSQL connection via Railway references |
| `GEOLITE_LICENSE_KEY` | Optional | MaxMind key to enable geolocation in analytics |
| `REDIRECT_STATUS_CODE` | Optional | `301` (cached) or `302` (always counted) |

> **Set your short domain and API key.** `DEFAULT_DOMAIN` must be a real short domain you add in Railway, or links won't be short. `INITIAL_API_KEY` creates the admin key on first boot — keep it secret.

> **Postgres, not SQLite.** This template uses PostgreSQL as Shlink recommends for production; SQLite is testing-only and risks breakage on updates. All links and visits persist in Postgres — back it up.

---

## Dependencies for Shlink Hosting

- Railway account — ~$5/month for Shlink and PostgreSQL
- PostgreSQL (included and wired via Railway references)
- A custom short domain with DNS pointed at Railway (recommended)
- Optional: a MaxMind GeoLite2 license key for geolocation analytics

### Deployment Dependencies

- [Shlink GitHub Repository](https://github.com/shlinkio/shlink)
- [Shlink Documentation](https://shlink.io/documentation/)
- [Shlink Environment Variables](https://shlink.io/documentation/environment-variables/)
- [Railway Private Networking](https://docs.railway.com/guides/private-networking)

### Implementation Details

The template runs the official `shlinkio/shlink:stable` image on port `8080` with a Railway-managed PostgreSQL database over the private network, connected via the `DB_DRIVER=postgres` and `DB_*` variables. PostgreSQL is used deliberately: Shlink's documentation states SQLite is for testing only and risks breakage on updates, while Postgres is recommended for production due to its indexing and concurrency performance under redirect load.

`DEFAULT_DOMAIN` defines the short domain used for generated links and should be a custom domain added to the Railway service with DNS pointed at it, since the value of a shortener is branded, genuinely short URLs. `INITIAL_API_KEY` creates an admin API key on first container startup, used to authenticate the REST API, CLI, and the separate shlink-web-client dashboard (deployable separately or via the hosted app.shlink.io client). `IS_HTTPS_ENABLED=true` aligns with Railway's automatic HTTPS.

Shlink tracks each visit with referrer, device, and optional geolocation (enabled with a MaxMind `GEOLITE_LICENSE_KEY`), generates QR codes per link, and exposes everything through its REST API. `REDIRECT_STATUS_CODE` selects cached 301 or always-counted 302 redirects. All short URLs, visits, tags, and API keys persist in PostgreSQL, the single backup target.

---

## Frequently Asked Questions

**Why must I set a custom short domain?** A shortener's whole value is short, branded links. `DEFAULT_DOMAIN` should be a custom domain like `s.yourbrand.com` added in Railway with DNS pointed at it — otherwise links use the long Railway subdomain and aren't actually short.

**How do I create short links?** Authenticate with your `INITIAL_API_KEY` and use the REST API, the CLI, or the shlink-web-client dashboard (point the hosted app.shlink.io client at your Railway API URL). The API key is created on first boot.

**Why PostgreSQL instead of SQLite?** Shlink's docs say SQLite is testing-only and can break on updates. This template uses PostgreSQL, recommended for production, so your instance stays reliable under real redirect traffic.

**Does it track analytics?** Yes — every visit records referrer and device, plus geolocation if you add a MaxMind GeoLite2 key, and each link gets a QR code. All of it stays on your instance.

**Where's the dashboard?** Shlink's server is API-only; the visual dashboard is a separate web client. Use the hosted client at app.shlink.io pointed at your API, or deploy shlink-web-client yourself.

---

## Why Deploy Shlink on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Shlink on Railway you get a self-hosted URL shortener with the essentials handled — PostgreSQL wired, an initial API key created, HTTPS enabled, and custom short domains supported. Own your branded links and every click's analytics, self-hosted on infrastructure you control.

## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/shlink-url-shortener
