OpenShort is an open source, self-hosted URL shortener for Docker, SQLite, and MySQL.
It is built for people who want a modern Bitly alternative they can run on their own infrastructure, with custom domains, a web dashboard, and easy short link management in a single container.
Project website: openshort.tech
- Self-hosted link shortener with a modern web dashboard
- Open source and easy to deploy with Docker or Docker Compose
- Works out of the box with SQLite, or with MySQL for external database setups
- Supports custom domains for branded short links
- Supports both permanent (301) and temporary (302) redirects
- Single-container architecture for simple deployments
OpenShort is a good fit for:
- Small businesses that want branded short links on their own domain
- Marketing teams and agencies that need self-hosted campaign links
- Developers and sysadmins looking for a Docker-based Bitly alternative
- Internal teams that want simple short URLs for tools, documentation, onboarding, or shared resources
- Create and manage short links from a web dashboard
- Custom domain support for branded short URLs
- Permanent (301) and temporary (302) redirects
- JWT-based authentication with ASP.NET Identity
- Modern UI built with Angular and PrimeNG
- Single-container architecture with backend and frontend in one image
- Flexible storage: zero-config SQLite by default or external MySQL
- Collision-resistant slug generation with automatic retry
Backend:
- .NET 9 (ASP.NET Core Web API)
- Entity Framework Core
- ASP.NET Identity for authentication
- FluentValidation
- NUnit for testing
Frontend:
- Angular 21 with standalone components
- PrimeNG UI components
- Tailwind CSS v3
- Reactive Forms
- Docker and Docker Compose installed
-
Clone the repository
git clone https://github.com/emanueledeamicis/OpenShort.git cd OpenShort -
Start the application (SQLite default) By default, OpenShort uses an embedded SQLite database. Zero configuration required.
docker compose up -d
Option: use MySQL To use MySQL instead of SQLite:
- Open
docker-compose.yml. - Add the
MYSQL_...environment variables to theopenshortservice. - Add a MySQL service definition such as
mysql:8.0, or point to an external MySQL server. - Run
docker compose up -d.
- Open
-
Access the application
- Dashboard (frontend):
http://<server-ip>:8081 - API and redirects (backend):
http://<server-ip>on port80
- Dashboard (frontend):
On the first startup, OpenShort creates the default administrator account:
- Username:
admin
When you open the dashboard for the first time, you will be prompted to choose the password for the admin account. No default password is shipped with the application.
After signing in, open the dashboard Security section to generate or manage the API key used by external integrations. Programmatic requests to the integration API must send that key in the X-Api-Key header.
docker compose downTo remove volumes and delete persisted SQLite data:
docker compose down -vYou can install OpenShort either by pulling the official Docker image or by using Docker Compose.
You can launch OpenShort instantly using the published image catokx/openshort:latest.
If you do not have an external database, use the embedded SQLite engine. Mapping /app/data is important if you want your links and settings to persist across container restarts.
docker run -d \
--name openshort \
-p 8081:8081 \
-p 8080:8080 \
-v openshort-data:/app/data \
--restart unless-stopped \
catokx/openshort:latestIf you already have a MySQL server running, you can connect OpenShort to it by passing the connection parameters. Since the data is stored externally, mapping a local volume is not strictly necessary.
docker run -d \
--name openshort \
-p 8081:8081 \
-p 8080:8080 \
-e MYSQL_HOST=your_mysql_host \
-e MYSQL_PORT=3306 \
-e MYSQL_DATABASE=openshort \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=your_secure_password \
--restart unless-stopped \
catokx/openshort:latestFor a more declarative setup, you can use the provided docker-compose.yml file.
-
Clone the repository
git clone https://github.com/emanueledeamicis/OpenShort.git cd OpenShort -
Start the services
docker compose up -d
-
Access the application
- Dashboard (frontend):
http://<server-ip>:8081 - API and redirects (backend):
http://<server-ip>on port80
- Dashboard (frontend):
If you are using the published image in docker-compose.yml:
-
Pull the newest image
docker compose pull
-
Recreate the container
docker compose up -d
-
Verify the update
docker compose ps docker compose logs --tail=100
This keeps your existing Docker volume data, including SQLite data and application settings.
If you started OpenShort with docker run, update it like this:
-
Pull the newest image
docker pull catokx/openshort:latest
-
Stop and remove the old container
docker stop openshort docker rm openshort
-
Start a new container with the same ports, volumes, and environment variables
docker run -d \ --name openshort \ -p 8081:8081 \ -p 8080:8080 \ -v openshort-data:/app/data \ --restart unless-stopped \ catokx/openshort:latest
When a new version is available, follow these steps to update your installation:
-
Pull the latest code
cd OpenShort git pull -
Rebuild and restart containers
docker compose down docker compose build --no-cache docker compose up -d
-
Verify the update
docker compose ps docker compose logs --tail=100
Note: The SQLite database and OpenShort settings, including JWT keys, are stored in Docker volumes. Do not delete the volumes with the
-vflag during an update if you rely on the embedded SQLite database.
OpenShort is a good fit if you are looking for:
- A self-hosted Bitly alternative
- A Docker-based URL shortener with SQLite or MySQL
- A branded short link service with custom domains
- A lightweight open source link shortener for personal use, internal tools, or small teams
OpenShort includes an integration-focused API guide for services and automation that use API key authentication.
Important:
- Integration API requests require an API key in the
X-Api-Keyheader - The API key is generated and managed from the OpenShort dashboard in the Security section
- Dashboard login uses JWT authentication, but external integrations should use the API key instead
Read the guide here:
cd backend/src/OpenShort.Api
dotnet runRun tests:
cd backend/tests/OpenShort.Tests
dotnet testEntity Framework migrations:
Note: OpenShort dynamically selects the database provider. By default, running these commands applies SQLite migrations. To run MySQL migrations during development, set the
MYSQL_HOSTenvironment variable before running them.
cd backend/src/OpenShort.Api
dotnet ef migrations add MigrationName --project ../OpenShort.Infrastructure
dotnet ef database update --project ../OpenShort.Infrastructurecd frontend
npm install
npm startFrontend dev server: http://localhost:4200
Build for production:
npm run buildOpenShort/
|-- backend/
| |-- src/
| | |-- OpenShort.Api/ # Web API controllers
| | |-- OpenShort.Core/ # Domain entities
| | `-- OpenShort.Infrastructure/ # Data access and services
| `-- tests/
| `-- OpenShort.Tests/ # Unit tests
|-- frontend/
| `-- src/
| |-- app/
| | |-- core/ # Services, guards, layout
| | `-- features/ # Feature modules
| `-- styles.css # Global styles
`-- docker-compose.yml # Docker orchestration
OpenShort is designed with a zero-config approach. By default, if you start the container without providing database parameters, it automatically creates and uses an embedded SQLite database. This is ideal for quick deployments, personal use, demos, and testing.
If you prefer an external database for larger workloads, OpenShort also supports MySQL through environment variables.
All environment variables can be configured directly inside the environment: section of your docker-compose.yml file. Most of them are optional.
# Optional: MySQL configuration
- MYSQL_HOST=your-mysql-server
- MYSQL_PORT=3306
- MYSQL_DATABASE=openshort
- MYSQL_USER=root
- MYSQL_PASSWORD=secure_password
# Security
- ASPNETCORE_ENVIRONMENT=Production
- ADMIN_PASSWORD_RESET=temporary_emergency_passwordNote: If your passwords or keys contain
$characters, you must escape them as$$indocker-compose.yml(for example,Password$$becomesPassword$$$$) so Docker does not interpret them as variables.
If you lose the admin password in a self-hosted deployment, you can reset it at container startup with the optional ADMIN_PASSWORD_RESET environment variable.
- Add
ADMIN_PASSWORD_RESET=your_new_temporary_passwordto the OpenShort container environment. - Restart the container.
- Sign in with username
adminand the new password. - Remove the environment variable from your deployment after the reset is complete.
The JWT key is auto-generated and securely saved into the database on the first application startup. You do not need to configure it manually for normal installations.
If you have specific needs such as cluster deployments or manual key rotation policies, you can still override the auto-generated key by explicitly passing it as an environment variable:
environment:
- JWT_SECRET_KEY=YourSuperSecretKeyOfAtLeast32CharactersLongIf you provide the key this way, OpenShort always prioritizes it over the one stored in SQLite or MySQL.
To use OpenShort with your own domains, follow these steps:
Point your domain or subdomain to your server IP address:
- Create an A record pointing to your server public IP
- Or create a CNAME record pointing to your server hostname
It is strongly recommended to run OpenShort behind a reverse proxy such as Nginx, Traefik, or Caddy with HTTPS enabled.
server {
listen 80;
server_name your-short-domain.com;
# Expose only REST APIs and short link redirects to the public internet.
# Keep the dashboard private when possible.
location / {
proxy_pass http://localhost:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Use Certbot and Let's Encrypt to obtain and manage certificates:
sudo certbot --nginx -d your-domain.comOnce your domain is pointing to the server, sign in to the OpenShort dashboard and add the domain in the Domains section to start using it for your short links.
MIT License - see the LICENSE file for details.
OpenShort is created by Emanuele De Amicis.
Contributions are welcome. Please open an issue or submit a pull request.