docker.recipes

Shlink URL Shortener

beginner

Self-hosted URL shortener with analytics and API.

Overview

Shlink is a powerful, open-source URL shortener developed by Alejandro Celaya that provides comprehensive link management with detailed analytics, QR code generation, and a robust REST API. Unlike simple URL shorteners, Shlink offers enterprise-grade features including geolocation tracking, visit analytics, custom domains, and extensive customization options while maintaining complete control over your data through self-hosting. This deployment creates a complete Shlink ecosystem using four specialized containers: the main Shlink API server for URL processing and analytics, a dedicated web client for user interface management, PostgreSQL for reliable data persistence, and Redis for high-performance caching and session management. The PostgreSQL database ensures ACID compliance and complex query capabilities for analytics, while Redis provides sub-millisecond response times for frequently accessed short URLs and caching layer optimization. This stack is ideal for organizations requiring branded short URLs with detailed analytics, marketing teams needing campaign tracking, developers building applications with URL shortening APIs, and privacy-conscious users who want full control over their link data. The combination of Shlink's feature-rich API with PostgreSQL's analytical capabilities and Redis's performance optimization creates a production-ready URL shortening service that scales from personal use to enterprise deployments.

Key Features

  • Custom domain support with SSL/HTTPS configuration for branded short URLs
  • Comprehensive visit analytics including geolocation, referrer tracking, and device detection
  • QR code generation with customizable size and format options for each shortened URL
  • REST API with authentication for programmatic URL creation and management
  • Real-time visit tracking with Redis-powered caching for instant response times
  • PostgreSQL-backed analytics with complex query capabilities for detailed reporting
  • Multi-user support with API key management and access control
  • URL validation, expiration dates, and maximum visit limits for enhanced control

Common Use Cases

  • 1Marketing campaigns requiring detailed click tracking and geographic analytics
  • 2SaaS applications needing embedded URL shortening with white-label branding
  • 3Enterprise organizations wanting self-hosted alternatives to bit.ly or tinyurl
  • 4Social media management tools requiring bulk URL shortening with analytics
  • 5E-commerce platforms tracking affiliate and referral link performance
  • 6Event management systems generating trackable registration and promotion links
  • 7Content creators and bloggers analyzing audience engagement across platforms

Prerequisites

  • Docker and Docker Compose installed with at least 2GB available RAM
  • Environment variables configured: SHORT_DOMAIN, DB_PASSWORD, API_KEY, GEOLITE_KEY
  • GeoLite2 license key from MaxMind for geolocation analytics features
  • Ports 8080 and 8081 available for Shlink API and web client access
  • Basic understanding of PostgreSQL for database maintenance and backups
  • Domain name configured if using custom short domains with DNS records

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 shlink:
3 image: shlinkio/shlink:stable
4 container_name: shlink
5 environment:
6 - DEFAULT_DOMAIN=${SHORT_DOMAIN}
7 - IS_HTTPS_ENABLED=false
8 - GEOLITE_LICENSE_KEY=${GEOLITE_KEY}
9 - DB_DRIVER=postgres
10 - DB_HOST=db
11 - DB_NAME=shlink
12 - DB_USER=shlink
13 - DB_PASSWORD=${DB_PASSWORD}
14 - REDIS_SERVERS=redis:6379
15 ports:
16 - "8080:8080"
17 depends_on:
18 - db
19 - redis
20 networks:
21 - shlink-network
22 restart: unless-stopped
23
24 shlink-web-client:
25 image: shlinkio/shlink-web-client:stable
26 container_name: shlink-web-client
27 environment:
28 - SHLINK_SERVER_URL=http://localhost:8080
29 - SHLINK_SERVER_API_KEY=${API_KEY}
30 ports:
31 - "8081:80"
32 depends_on:
33 - shlink
34 networks:
35 - shlink-network
36 restart: unless-stopped
37
38 db:
39 image: postgres:15-alpine
40 container_name: shlink-db
41 environment:
42 - POSTGRES_USER=shlink
43 - POSTGRES_PASSWORD=${DB_PASSWORD}
44 - POSTGRES_DB=shlink
45 volumes:
46 - postgres-data:/var/lib/postgresql/data
47 networks:
48 - shlink-network
49 restart: unless-stopped
50
51 redis:
52 image: redis:7-alpine
53 container_name: shlink-redis
54 volumes:
55 - redis-data:/data
56 networks:
57 - shlink-network
58 restart: unless-stopped
59
60volumes:
61 postgres-data:
62 redis-data:
63
64networks:
65 shlink-network:
66 driver: bridge

.env Template

.env
1# Shlink
2SHORT_DOMAIN=short.example.com
3DB_PASSWORD=secure_shlink_password
4
5# Get from maxmind.com for geolocation
6GEOLITE_KEY=your_geolite_license_key
7
8# Generate API key: docker exec shlink shlink api-key:generate
9API_KEY=your_api_key

Usage Notes

  1. 1Shlink API at http://localhost:8080
  2. 2Web client at http://localhost:8081
  3. 3Generate API key via CLI
  4. 4QR codes and visit tracking
  5. 5REST API available

Individual Services(4 services)

Copy individual services to mix and match with your existing compose files.

shlink
shlink:
  image: shlinkio/shlink:stable
  container_name: shlink
  environment:
    - DEFAULT_DOMAIN=${SHORT_DOMAIN}
    - IS_HTTPS_ENABLED=false
    - GEOLITE_LICENSE_KEY=${GEOLITE_KEY}
    - DB_DRIVER=postgres
    - DB_HOST=db
    - DB_NAME=shlink
    - DB_USER=shlink
    - DB_PASSWORD=${DB_PASSWORD}
    - REDIS_SERVERS=redis:6379
  ports:
    - "8080:8080"
  depends_on:
    - db
    - redis
  networks:
    - shlink-network
  restart: unless-stopped
shlink-web-client
shlink-web-client:
  image: shlinkio/shlink-web-client:stable
  container_name: shlink-web-client
  environment:
    - SHLINK_SERVER_URL=http://localhost:8080
    - SHLINK_SERVER_API_KEY=${API_KEY}
  ports:
    - "8081:80"
  depends_on:
    - shlink
  networks:
    - shlink-network
  restart: unless-stopped
db
db:
  image: postgres:15-alpine
  container_name: shlink-db
  environment:
    - POSTGRES_USER=shlink
    - POSTGRES_PASSWORD=${DB_PASSWORD}
    - POSTGRES_DB=shlink
  volumes:
    - postgres-data:/var/lib/postgresql/data
  networks:
    - shlink-network
  restart: unless-stopped
redis
redis:
  image: redis:7-alpine
  container_name: shlink-redis
  volumes:
    - redis-data:/data
  networks:
    - shlink-network
  restart: unless-stopped

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 shlink:
5 image: shlinkio/shlink:stable
6 container_name: shlink
7 environment:
8 - DEFAULT_DOMAIN=${SHORT_DOMAIN}
9 - IS_HTTPS_ENABLED=false
10 - GEOLITE_LICENSE_KEY=${GEOLITE_KEY}
11 - DB_DRIVER=postgres
12 - DB_HOST=db
13 - DB_NAME=shlink
14 - DB_USER=shlink
15 - DB_PASSWORD=${DB_PASSWORD}
16 - REDIS_SERVERS=redis:6379
17 ports:
18 - "8080:8080"
19 depends_on:
20 - db
21 - redis
22 networks:
23 - shlink-network
24 restart: unless-stopped
25
26 shlink-web-client:
27 image: shlinkio/shlink-web-client:stable
28 container_name: shlink-web-client
29 environment:
30 - SHLINK_SERVER_URL=http://localhost:8080
31 - SHLINK_SERVER_API_KEY=${API_KEY}
32 ports:
33 - "8081:80"
34 depends_on:
35 - shlink
36 networks:
37 - shlink-network
38 restart: unless-stopped
39
40 db:
41 image: postgres:15-alpine
42 container_name: shlink-db
43 environment:
44 - POSTGRES_USER=shlink
45 - POSTGRES_PASSWORD=${DB_PASSWORD}
46 - POSTGRES_DB=shlink
47 volumes:
48 - postgres-data:/var/lib/postgresql/data
49 networks:
50 - shlink-network
51 restart: unless-stopped
52
53 redis:
54 image: redis:7-alpine
55 container_name: shlink-redis
56 volumes:
57 - redis-data:/data
58 networks:
59 - shlink-network
60 restart: unless-stopped
61
62volumes:
63 postgres-data:
64 redis-data:
65
66networks:
67 shlink-network:
68 driver: bridge
69EOF
70
71# 2. Create the .env file
72cat > .env << 'EOF'
73# Shlink
74SHORT_DOMAIN=short.example.com
75DB_PASSWORD=secure_shlink_password
76
77# Get from maxmind.com for geolocation
78GEOLITE_KEY=your_geolite_license_key
79
80# Generate API key: docker exec shlink shlink api-key:generate
81API_KEY=your_api_key
82EOF
83
84# 3. Start the services
85docker compose up -d
86
87# 4. View logs
88docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/shlink-url-shortener/run | bash

Troubleshooting

  • Shlink container fails to connect to database: Verify DB_PASSWORD matches between shlink and db services, ensure PostgreSQL is fully initialized before Shlink starts
  • Web client shows 'Server not accessible': Check SHLINK_SERVER_URL environment variable and ensure shlink container is running on port 8080
  • Geolocation data not appearing in analytics: Verify GEOLITE_LICENSE_KEY is valid and MaxMind database downloads are not blocked by firewall
  • Redis connection errors in Shlink logs: Confirm redis container is running and accessible on port 6379, check network connectivity within shlink-network
  • API key authentication fails: Generate new API key using Shlink CLI command 'bin/cli api-key:generate' inside the shlink container
  • Short URLs returning 404 errors: Verify DEFAULT_DOMAIN environment variable matches your intended domain and DNS configuration

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space