YOURLS is the old-school option in the best possible sense.
It is a small PHP application that does one job: run your own URL shortener. You get an admin panel, short-link creation, click statistics, an API, bookmarklets, and a plugin system without adding Redis, ClickHouse, queue workers, object storage, or a serverless deployment model.
If you want the lightest practical self-hosted shortener with a long history, YOURLS is still worth considering.
What is YOURLS?
YOURLS stands for “Your Own URL Shortener”.
I inspected commit:
9add23549f4ef2d1a8a2c883778a8a60b3e64d07
The current branch reports:
1.10.7-dev
The latest release tag in the checked-out repo was:
1.10.6
For the Docker setup, I pinned the image to:
yourls:1.10.6-apache
What You Get
YOURLS includes the practical shortener basics:
- private admin interface;
- short-link creation and editing;
- custom keywords;
- click counters;
- per-link statistics pages;
- referrer and visitor reports;
- bookmarklets;
- REST-like API through
yourls-api.php; - plugin architecture;
- sample public front-end and public API files;
- support for running private or public instances.
The UI is not modern SaaS-style, but it is functional and fast. This is a small admin tool, not a marketing analytics suite.
Architecture
YOURLS is a traditional PHP web app.
The stack is:
- PHP 8.1+ application code.
- Apache in the official Docker image used here.
- PDO MySQL database access.
- MySQL or MariaDB for persistence.
- Server-rendered admin UI.
- Plugin hooks for extending core behavior.
- API endpoint at
yourls-api.php.
The request shape is simple:
Browser/API client -> YOURLS PHP app -> MariaDB
There are no required background workers, queue services, Redis caches, OLAP engines, or object-storage buckets.
Home-Lab Compose Review
There was already a YOURLS folder in Home-Lab.
The old setup worked as a rough reference, but it had avoidable problems:
- duplicated compose files;
- hardcoded database passwords;
- hardcoded LAN IP;
latestimage tags;- old
8080:80container-port mapping; - old Compose
versionfield; - no database healthcheck.
I replaced it with a single canonical compose file using .env, pinned images, MariaDB healthchecks, and the current official image port.
Self-Hosting with Docker
The reusable Home-Lab compose file is here:
The site includes the same Compose file from the local snippets folder:
assets/snippets/yourls/docker-compose.yml
Pre-Requisites - Docker
Install Docker on your system before proceeding:
- Linux: Official Docker Engine install guide
- Windows / Mac: Docker Desktop
Verify installation: docker --version && docker compose version
#https://dbt3ch.com/books/yourls/page/docker-compose-stack
version: '3.8'
services:
db:
image: mariadb:latest
container_name: yourls-db
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: yourls
MYSQL_USER: yourls
MYSQL_PASSWORD: yourlsdbpassword
volumes:
- yourls-db-data:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
yourls:
image: yourls:latest
container_name: yourls
depends_on:
- db
ports:
- "8080:80" # Expose YOURLS on port 8080 of the host
environment:
YOURLS_SITE: http://192.168.3.200:8080 #http://localhost:8080
YOURLS_DB_PASS: yourlsdbpassword
YOURLS_DB_USER: yourls
YOURLS_DB_NAME: yourls
YOURLS_DB_HOST: db # Use the service name of the MariaDB container
YOURLS_SKIP_INIT: "false"
volumes:
- yourls-data:/var/www/html
volumes:
yourls-data:
yourls-db-data:
# version: '3.1'
# services:
# yourls:
# image: yourls:latest
# container_name: yourls
# depends_on:
# - db
# ports:
# - "8080:80" # Expose YOURLS on port 8080 of the host
# environment:
# YOURLS_SITE: http://localhost:8080
# YOURLS_DB_PASS: yourlsdbpassword
# YOURLS_DB_USER: yourls
# YOURLS_DB_NAME: yourls
# # You can set the following to "true" to skip the install if this is a re-deployment
# YOURLS_SKIP_INIT: "false"
# volumes:
# - yourls-data:/var/www/html # Persist your data here
# db:
# image: mysql:5.7
# container_name: yourls-db
# environment:
# MYSQL_ROOT_PASSWORD: rootpassword
# MYSQL_DATABASE: yourls
# MYSQL_USER: yourls
# MYSQL_PASSWORD: yourlsdbpassword
# volumes:
# - yourls-db-data:/var/lib/mysql # Persist database data here
# command: '--default-authentication-plugin=mysql_native_password' # Needed for MySQL 8+
# volumes:
# yourls-data:
# yourls-db-data:
#https://github.com/YOURLS/YOURLS
#self hosted URL shortener in PHP
#https://yourls.org/
#https://hub.docker.com/_/yourls
#https://github.com/YOURLS/awesome
#https://www.youtube.com/watch?v=tXM-csqijdw
#https://www.youtube.com/watch?v=WNVVlV75hs4 #one DB multiple containersPrepare the environment:
cd assets/snippets/yourls
cp .env.sample .env
Generate secrets:
openssl rand -base64 32
openssl rand -base64 32
openssl rand -base64 32
Use those generated values for:
YOURLS_PASS
MARIADB_ROOT_PASSWORD
MARIADB_PASSWORD
Start the stack:
docker compose up -d
The default local admin URL is:
http://localhost:8789/admin/
On the first run, go to:
http://localhost:8789/admin/install.php
and click the install button.
Domain Configuration
YOURLS_SITE must match the public URL you will actually use, without a trailing slash.
Local examples:
YOURLS_SITE=http://localhost:8789
YOURLS_SITE=http://192.168.1.2:8789
Public example:
YOURLS_SITE=https://s.example.com
For a public deployment, put YOURLS behind HTTPS:
https://s.example.com -> reverse proxy -> http://yourls:8080
If YOURLS_SITE does not match the browser-facing URL, generated short links and asset URLs can be wrong.
API Notes
YOURLS exposes API actions through:
/yourls-api.php
Common API use cases include:
- creating a short URL;
- requesting JSON, XML, or plain text output;
- checking link statistics;
- using a signature token instead of sending the password directly;
- adding custom API actions through plugins.
For private instances, keep the API private unless you have a specific public-use case.
Plugin Model
YOURLS has a long-standing plugin API.
Plugins live under:
user/plugins
That is one reason the compose file persists:
/var/www/html
so plugins, uploaded custom files, and generated config survive container replacement.
For a cleaner production setup, I would keep custom plugins under version control and mount only the plugin directories you intentionally manage.
Field Test
I smoke-tested the fixed Home-Lab compose with disposable containers and volumes.
Command shape:
YOURLS_PORT=8789 \
YOURLS_SITE=http://localhost:8789 \
YOURLS_USER=admin \
YOURLS_PASS=test-admin-password \
MARIADB_ROOT_PASSWORD=test-root-password \
MARIADB_PASSWORD=test-db-password \
docker compose -f /home/jalcocert/Desktop/Home-Lab/yourls/docker-compose.yml -p yourls_smoke up -d
Observed:
- MariaDB 11.4 became healthy.
- YOURLS copied its application files into
/var/www/html. GET /returned HTTP403, which is expected before adding a public front page.GET /admin/returned HTTP307to/admin/install.php.GET /admin/install.phpreturned HTTP200.POST /admin/install.phpcompleted the install with HTTP200.GET /admin/returned HTTP200after installation.- MariaDB contained the expected tables:
yourls_log,yourls_options, andyourls_url.
Then I removed the smoke-test containers and volumes:
docker compose -p yourls_smoke down -v --remove-orphans
YOURLS vs Shlink vs Kutt vs Dub
YOURLS is the simplest traditional option.
Compared with Shlink:
- YOURLS has a built-in admin UI.
- Shlink has a stronger API/CLI-first backend model.
- Shlink has a separate web client.
Compared with Kutt:
- YOURLS is older and simpler.
- Kutt feels more like a complete modern web app.
- YOURLS has a large plugin ecosystem.
Compared with Dub:
- YOURLS is tiny.
- Dub is a cloud-native attribution platform.
- YOURLS needs PHP plus MySQL/MariaDB; Dub expects several specialized services.
See also:
FAQ
Does YOURLS have a UI?
Yes. YOURLS has a built-in admin UI at /admin/.
Why does / return 403?
That is normal for the official Docker image unless you add a public front page. Use /admin/ for management, or create a public page using the sample files if you want visitors to create links.
Does YOURLS require MySQL or MariaDB?
Yes. YOURLS stores links, options, and visit logs in a MySQL-compatible database. The Home-Lab snippet uses MariaDB.
Does YOURLS require Redis?
No. Redis is not part of the default YOURLS stack.
What additional services does YOURLS use?
The default Home-Lab stack uses only:
YOURLS
MariaDB
Additional infrastructure is optional:
- MariaDB/MySQL: required database layer. MariaDB and MySQL are self-hostable; MariaDB is the FOSS default I used here.
- Reverse proxy: optional but recommended for HTTPS. Caddy, Nginx, Traefik, and Apache are all self-hostable open-source options.
- Plugins: optional. Plugin quality and dependencies vary by plugin; YOURLS itself does not require a plugin service.
- External analytics/marketing tools: not required by core YOURLS. Add them only through plugins if you want them.
YOURLS does not need ClickHouse, Redis, QStash, S3, object storage, or a cloud account for normal self-hosting.
Can YOURLS be public?
Yes, but decide what “public” means. You can expose only redirects and the admin UI behind authentication, or you can build a public front page that lets visitors create short links. For most home-lab uses, keep link creation private.
Can I run YOURLS behind Cloudflare Tunnel?
Yes. Put YOURLS behind your tunnel or reverse proxy, set YOURLS_SITE to the public HTTPS URL, and make sure /admin/ is protected with strong credentials.
Is YOURLS still maintained?
Yes. The checked-out repo has recent release tags up to 1.10.6, and the current branch points at 1.10.7-dev.
What is the simplest deployment?
One YOURLS container and one MariaDB container.
That is the setup in this post.
Verdict
YOURLS is the URL shortener I would choose when I want something classic, small, and boring in a good way.
It does not have the modern polish of Kutt, the API/CLI structure of Shlink, or the attribution pipeline of Dub. But it is easy to run, easy to understand, plugin-friendly, and perfectly fine for a personal or small-team branded short-link service.
Comments