Deploy Shlink — Self-Hosted URL Shortener & Bitly Alternative
Self-host Shlink — branded short links, analytics & REST API
Just deployed
/var/lib/postgresql/data
Shlink Web Client
Just deployed
Shlink
Just deployed
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
- Click Deploy on Railway — Shlink and PostgreSQL build and wire together (~3 minutes)
- Set
DEFAULT_DOMAINto your custom short domain and add that domain in Railway's settings - Set a strong
INITIAL_API_KEYand confirm the database is connected - Point DNS for your short domain at Railway, so links resolve over HTTPS
- 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/xyzlinks 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_DOMAINmust be a real short domain you add in Railway, or links won't be short.INITIAL_API_KEYcreates 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
- Shlink Documentation
- Shlink Environment Variables
- Railway 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.
Template Content
Shlink Web Client
MykalMachon/shlink-on-railwayUSERNAME
Username for the web client via HTTP basic auth
Shlink
shlinkio/shlink:stable