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.

Quick Start

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 80 and 8081 available (or configure alternatives)
  • Optional: a custom domain with DNS access for branded short URLs
Note

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)

terminal
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.

Up and running

Dashboard available at http://localhost:8081 · Redirect API at http://localhost:80

MySQL mode

terminal
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
Security

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

terminal
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):

docker-compose.yml
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

terminal
docker compose up -d

OpenShort will start and automatically initialize the SQLite database. No additional setup required.

Success

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.

docker-compose.mysql.yml
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:
Security

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

PortServiceDescription
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:

docker-compose.yml — port override
ports:
  - "443:80"    # HTTPS → redirect API
  - "3000:8081" # Custom port → dashboard

Configuration

OpenShort is configured via environment variables. The following variables are available:

VariableDefaultDescription
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.
Default database

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

  1. Point your domain's DNS A record to your server's IP address.
  2. Set up a reverse proxy (e.g., Nginx or Caddy) to forward traffic to OpenShort's port 80.
  3. Configure SSL/TLS for HTTPS (strongly recommended for production).
  4. Create short links in the dashboard using your custom domain as the base URL.

Example: Nginx reverse proxy

/etc/nginx/sites-available/openshort
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.

TypeHTTP StatusUse 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.
SEO Note

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.

  1. Open the dashboard at http://localhost:8081 (or your configured domain).
  2. You'll be prompted to set a password for the admin account.
  3. After setting your password, you'll be logged into the dashboard.
Security

Choose a strong password. OpenShort uses JWT-based authentication, but your password is the primary credential protecting your link management interface.

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.

MethodEndpointDescription
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.

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

  1. Fork and clone the repository
  2. Install .NET 9 SDK and Node.js 20+
  3. Run the API: cd src/OpenShort.Api && dotnet run
  4. 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.