OpenShort Documentation
Welcome to the OpenShort documentation. OpenShort is a self-hosted, open-source URL shortener built with .NET 9 and Angular 21. It gives you full control over your link infrastructure — deploy it on your own server, use your own domain, and keep your data private.
Want to get started immediately? Jump to the Installation section — you'll be up and running in under 5 minutes.
What is OpenShort?
OpenShort is designed as a privacy-first alternative to commercial URL shorteners like Bitly or TinyURL. Instead of relying on a third-party service that tracks your links and owns your data, OpenShort lets you run the entire system on your own infrastructure.
Key properties:
- Self-hosted — runs entirely on your server or VPS
- Open source — MIT licensed, inspect and modify freely
- Single container — ships as one Docker image with embedded SQLite
- Custom domains — use your own branded short domain
- REST API — integrate link creation into your workflows
Prerequisites
Before installing OpenShort, make sure you have the following:
- Docker (v20.10+) and Docker Compose (v2.0+) installed on your server
- A server or VPS with at least 512 MB RAM (1 GB recommended)
- Ports
80and8081available (or configure alternatives) - Optional: a custom domain with DNS access for branded short URLs
If you want to run OpenShort without Docker, you'll need .NET 9 SDK and Node.js 20+. Docker is strongly recommended for simplicity.
Installation — Docker Run (Quick Start)
The fastest way to get OpenShort running is with a single docker run command using the public image. No cloning or compose files needed.
SQLite mode (default)
docker run -d \
--name openshort \
-p 80:80 \
-p 8081:8081 \
-v openshort-data:/app/data \
--restart unless-stopped \
ghcr.io/emanueledeamicis/openshort:latest OpenShort will start with an embedded SQLite database. Data is persisted in the openshort-data Docker volume.
Dashboard available at http://localhost:8081 · Redirect API at http://localhost:80
MySQL mode
docker run -d \
--name openshort \
-p 80:80 \
-p 8081:8081 \
-e MYSQL_HOST=your_mysql_host \
-e MYSQL_PORT=3306 \
-e MYSQL_DATABASE=openshort \
-e MYSQL_USER=openshort \
-e MYSQL_PASSWORD=your_secure_password \
--restart unless-stopped \
ghcr.io/emanueledeamicis/openshort:latest Replace all placeholder values with your actual MySQL credentials before running in production.
Installation — Docker Compose with SQLite
For a more structured setup, use Docker Compose with the bundled SQLite database. This requires no external database setup.
Step 1 — Clone the repository
git clone https://github.com/emanueledeamicis/openshort.git
cd openshort Step 2 — Create your compose file
Create a docker-compose.yml file (or use the one from the repository):
services:
openshort:
image: ghcr.io/emanueledeamicis/openshort:latest
ports:
- "80:80"
- "8081:8081"
volumes:
- ./data:/app/data
restart: unless-stopped Step 3 — Start the service
docker compose up -d OpenShort will start and automatically initialize the SQLite database. No additional setup required.
Once running, the dashboard is available at http://localhost:8081 and the redirect API at http://localhost:80.
Installation — Docker Compose with MySQL
For production deployments or when you need a more scalable database, OpenShort supports MySQL. Configure it via environment variables.
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: openshort
MYSQL_USER: openshort
MYSQL_PASSWORD: yourpassword
volumes:
- mysql_data:/var/lib/mysql
restart: unless-stopped
openshort:
image: ghcr.io/emanueledeamicis/openshort:latest
ports:
- "80:80"
- "8081:8081"
environment:
MYSQL_HOST: db
MYSQL_PORT: 3306
MYSQL_DATABASE: openshort
MYSQL_USER: openshort
MYSQL_PASSWORD: yourpassword
depends_on:
- db
restart: unless-stopped
volumes:
mysql_data: Replace all placeholder passwords with strong, unique values before deploying to production. Consider using Docker secrets or an .env file for sensitive values.
Ports & Access
| Port | Service | Description |
|---|---|---|
80 | Redirect API | Handles incoming short URL requests and performs redirects. This is the port users visit when clicking a short link. |
8081 | Dashboard | The Angular web dashboard for managing links. Access this to create, edit, and delete URLs. |
You can remap these ports in the Docker Compose file. For example, to use port 3000 for the dashboard:
ports:
- "443:80" # HTTPS → redirect API
- "3000:8081" # Custom port → dashboard Configuration
OpenShort is configured via environment variables. The following variables are available:
| Variable | Default | Description |
|---|---|---|
MYSQL_HOST | — | MySQL server hostname. If not set, SQLite is used. |
MYSQL_PORT | 3306 | MySQL server port. |
MYSQL_DATABASE | — | Name of the MySQL database to use. |
MYSQL_USER | — | MySQL username for authentication. |
MYSQL_PASSWORD | — | MySQL password for authentication. |
When no MySQL environment variables are set, OpenShort automatically uses an embedded SQLite database stored in /app/data/openshort.db. Mount a volume to persist data between container restarts.
Custom Domains
OpenShort supports custom domains so you can use branded short URLs like go.yourcompany.com/slug instead of your server's IP address.
Setup overview
- Point your domain's DNS A record to your server's IP address.
- Set up a reverse proxy (e.g., Nginx or Caddy) to forward traffic to OpenShort's port
80. - Configure SSL/TLS for HTTPS (strongly recommended for production).
- Create short links in the dashboard using your custom domain as the base URL.
Example: Nginx reverse proxy
server {
listen 80;
server_name go.yourcompany.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name go.yourcompany.com;
ssl_certificate /etc/letsencrypt/live/go.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/go.yourcompany.com/privkey.pem;
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;
}
} Redirect Types
OpenShort supports two HTTP redirect types, which affect how browsers and search engines handle the redirect.
| Type | HTTP Status | Use Case |
|---|---|---|
| Permanent | 301 Moved Permanently | Use when the destination URL will not change. Browsers and search engines cache this redirect. Best for stable marketing links. |
| Temporary | 302 Found | Use when the destination may change in the future. Not cached by browsers. Best for A/B testing, campaigns, or dynamic destinations. |
Use 301 redirects cautiously — once a browser caches them, changing the destination requires users to clear their cache. When in doubt, use 302.
First Login
On the first startup, OpenShort automatically creates an admin user account. No default credentials are shipped — you set your own password during the initial setup flow.
- Open the dashboard at
http://localhost:8081(or your configured domain). - You'll be prompted to set a password for the admin account.
- After setting your password, you'll be logged into the dashboard.
Choose a strong password. OpenShort uses JWT-based authentication, but your password is the primary credential protecting your link management interface.
Creating Links
You can create short links either via the web dashboard or the REST API.
Via the dashboard
- Log into the dashboard at port
8081. - Click "New Link" or the "+" button.
- Enter the destination (long) URL.
- Optionally customize the slug (the short part of the URL). If left blank, a random collision-resistant slug is generated automatically.
- Choose the redirect type (301 or 302).
- Click "Create".
Via the API
Generate an API key from the dashboard, then use it in the X-Api-Key header:
curl -X POST http://localhost:80/api/links \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-api-key-here" \
-d '{
"url": "https://example.com/very/long/path?with=params",
"slug": "my-link",
"redirectType": 302
}' Managing Links
The dashboard provides a full interface for link management:
- List view — see all your short links with their destination URLs and redirect type.
- Edit — update the destination URL, slug, or redirect type of any existing link.
- Delete — permanently remove a link. Deleted links will return a 404 to visitors.
- Copy — quickly copy the short URL to clipboard.
API Reference
OpenShort exposes a REST API on port 80. All management endpoints require an API key passed via the X-Api-Key header. Redirect endpoints are public.
| Method | Endpoint | Description |
|---|---|---|
GET | /api/links | List all short links. Requires authentication. |
POST | /api/links | Create a new short link. Requires authentication. |
PUT | /api/links/{id} | Update an existing link. Requires authentication. |
DELETE | /api/links/{id} | Delete a link. Requires authentication. |
GET | /{slug} | Public redirect endpoint. Resolves slug and redirects the visitor. |
Authentication
All management API endpoints are authenticated via an API key passed in the X-Api-Key request header.
Generating an API Key API keys are created from the OpenShort dashboard by an authenticated administrator. Log into the dashboard at port 8081, navigate to the API keys section, and generate a new key. Treat it like a password — store it securely and regenerate it if compromised (regenerating automatically invalidates the old key).
Include the key in every API request using the X-Api-Key header:
HTTP Header X-Api-Key: your-api-key-here
Security Never expose your API key in client-side code or public repositories. Use environment variables or secrets management to store it in scripts and automation pipelines.
Links Endpoints
GET /api/links
Returns all short links in the system.
Response example [
{
"id": "abc123",
"slug": "my-link",
"url": "https://example.com/long/path",
"redirectType": 302,
"createdAt": "2026-01-15T10:00:00Z"
}
]
POST /api/links
Creates a new short link. The slug field is optional — if omitted, a random slug is generated.
Request body {
"url": "https://example.com/destination",
"slug": "optional-custom-slug",
"redirectType": 302
}
Contributing
OpenShort is open source and contributions are welcome! Here's how to get involved:
- Bug reports — open an issue on GitHub Issues
- Feature requests — start a discussion in GitHub Issues
- Pull requests — fork the repo, make your changes, and open a PR
Development setup
- Fork and clone the repository
- Install .NET 9 SDK and Node.js 20+
- Run the API:
cd src/OpenShort.Api && dotnet run - Run the dashboard:
cd src/OpenShort.Dashboard && npm install && npm start
License
OpenShort is released under the MIT License. You are free to use, modify, and distribute it — including for commercial purposes — as long as the original license and copyright notice are included.
See the full license text in the LICENSE file on GitHub.