Shlink on Ubuntu 24.04 on Azure User Guide
Overview
Shlink is a self hosted URL shortener that gives you complete ownership of your short links, their data and their analytics. This cloudimg image runs Shlink 5.1.0 behind nginx with PHP 8.4 FPM on a hardened, fully patched Ubuntu 24.04 LTS base. Short URLs, their visits and all analytics are stored in a SQLite database on a dedicated Azure data disk mounted at /opt/shlink-data, so the data tier is separate from the operating system disk. The official Shlink web client, a single page application, is served on the same VM and is pre connected to the local REST API.
The Shlink REST API and short URL redirects are served at the VM root, with the API under the /rest path. Browsing to the VM address opens the web client management console. A systemd timer runs Shlink's visit processing every fifteen minutes.
A per VM administrator API key is generated on the first boot of every deployed VM. Two VMs launched from the same image never share a key, and no demo data, short URLs or keys ship in the image. The generated key is written to /root/shlink-credentials.txt with mode 0600 so only the root user can read it, and the web client's server entry is wired to it automatically.
On first boot the image reads the VM address from Azure instance metadata and uses it as Shlink's default short domain, so generated short URLs use the address customers reach the VM on. To serve short links on your own branded domain, set a custom domain as described later in this guide.
What is included:
- Shlink 5.1.0 served by nginx and PHP 8.4 FPM, managed by systemd
- The official Shlink web client 4.7.1, pre connected to the local REST API
- A SQLite database on a dedicated Azure data disk at
/opt/shlink-data - A per VM administrator API key generated on first boot and recorded in a root only file
shlink-visits.timer, which processes and geolocates visits every fifteen minutes- The REST API under
/restfor programmatic link creation and analytics - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point; size up for higher redirect volumes. Network security group inbound: allow 22/tcp from your management network and 80/tcp (and 443/tcp once you add TLS) from the networks that will use your short links. The Azure CLI is required only if you deploy from the command line.
Step 1: Launch from the Azure Marketplace
Sign in to the Azure portal, select Create a resource, and search the Marketplace for Shlink on Ubuntu 24.04 LTS by cloudimg. Select the offer, choose the plan, and select Create.
On the Basics tab pick your subscription and resource group, a region, and a VM size of Standard_B2s or larger. Set the authentication type to SSH public key, the username to azureuser, and provide your public key. On the Networking tab select your VNet and subnet and a network security group that allows inbound 22/tcp and 80/tcp. Review and create. First boot initialisation completes about a minute after the VM reaches the Running state.
Step 2: Launch from the Azure CLI
The following block creates a VM from the cloudimg Shlink image. Replace the placeholders with your own values. The image reference is shown on the Marketplace offer page.
az vm create \
--resource-group <your-resource-group> \
--name shlink-01 \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values <path-to-your-public-key> \
--public-ip-sku Standard \
--nsg-rule SSH
After the VM is running, open ports 80 (and 443 once you add TLS) on its network security group, then retrieve its public IP with az vm show -d -g <your-resource-group> -n shlink-01 --query publicIps -o tsv.
Step 3: Connect and Retrieve the API Key
Connect over SSH as azureuser with the VM's public IP address:
ssh azureuser@<public-ip>
Once connected, read the generated API key. It is stored in a root only file, so use sudo:
sudo cat /root/shlink-credentials.txt
The file contains the web client URL, the REST API base URL, and the per VM API key:

Step 4: Confirm the Service Is Healthy
Shlink exposes an unauthenticated health endpoint. Confirm it reports pass and the expected version, and check that nginx and PHP FPM are active:
systemctl is-active nginx php8.4-fpm

curl -s http://127.0.0.1/rest/health
A healthy VM returns a JSON document containing "status":"pass" and "version":"5.1.0".

Step 5: Open the Shlink Web Client
Browse to http://<public-ip>/ in a web browser. The Shlink web client loads and automatically connects to this VM using the generated API key, so no manual server set up is required. The Overview page shows total visits, the number of short URLs, recently created links, and a form to create a new short URL.

The List short URLs page lists every short URL with its destination, tags and visit count, and provides search and filtering.

Step 6: Create a Short URL
Open Create short URL in the web client, paste the long URL you want to shorten into URL to be shortened, optionally set a title, custom slug, tags or access limits, and select Save. The web client returns the generated short URL, which you can copy with one click.

You can also create a short URL directly through the REST API with the key from step 3. The following command reads the key from the credentials file and creates a short URL for https://www.cloudimg.co.uk:
SHLINK_KEY=$(sudo grep '^shlink.api.key=' /root/shlink-credentials.txt | cut -d= -f2-)
curl -s -X POST -H "X-Api-Key: ${SHLINK_KEY}" -H 'Content-Type: application/json' \
-d '{"longUrl":"https://www.cloudimg.co.uk","findIfExists":true}' \
http://127.0.0.1/rest/v3/short-urls
The response is a JSON document describing the new short URL, including its shortCode and full shortUrl.
Step 7: List and Protect the REST API
The same key authenticates read requests. List all short URLs:
SHLINK_KEY=$(sudo grep '^shlink.api.key=' /root/shlink-credentials.txt | cut -d= -f2-)
curl -s -H "X-Api-Key: ${SHLINK_KEY}" http://127.0.0.1/rest/v3/short-urls
Requests without a valid key are rejected. The following request omits the header and returns HTTP 401, confirming the API is protected:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/rest/v3/short-urls
Step 8: Read Visit Analytics
Every time a short URL is followed, Shlink records a visit. In the web client, select the visit count beside any short URL to open its analytics, which break visits down by time, by context (browser, operating system, referrer) and by location.

Visit geolocation is resolved by a systemd timer, shlink-visits.timer, which runs every fifteen minutes. Inspect its status with:
systemctl status shlink-visits.timer --no-pager
Geolocation requires a free MaxMind GeoLite2 license key. Without one, visits are still recorded and analysed by time and context; only the location breakdown is unavailable. To enable location resolution, obtain a license key from MaxMind, add 'GEOLITE_LICENSE_KEY' => '<your-key>', to the array in /opt/shlink/config/params/generated_config.php, and run sudo -u www-data php8.4 /opt/shlink/bin/cli visit:download-db.
Step 9: Manage API Keys
Shlink supports multiple API keys with different roles. List the keys on the VM:
sudo -u www-data php8.4 /opt/shlink/bin/cli api-key:list
To generate an additional key, for example for a separate application, use the api-key:generate command. Run it interactively from your SSH session and record the key it prints, because Shlink only shows the full key once at creation:
sudo -u www-data php8.4 /opt/shlink/bin/cli api-key:generate --name=my-application
Step 10: Use a Custom Short Domain
By default short URLs use the VM's address. To serve short links on your own domain, point a DNS record at the VM, then edit /opt/shlink/config/params/generated_config.php and set 'DEFAULT_DOMAIN' to your domain and 'IS_HTTPS_ENABLED' to true once you have TLS in place. Restart the service afterwards with sudo systemctl restart php8.4-fpm nginx.
Step 11: Enable HTTPS
For production use, terminate TLS in front of Shlink. The simplest approach on a single VM is Let's Encrypt with Certbot. Because Certbot prompts interactively for an email address and agreement to the terms of service, run it directly in your SSH session rather than from a script:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com
Certbot edits the nginx configuration to serve HTTPS and installs a renewal timer. After it completes, set 'IS_HTTPS_ENABLED' => true in the configuration file and reload nginx with sudo systemctl reload nginx.
Step 12: Where Your Data Lives and How to Back It Up
All Shlink data lives in the SQLite database on the dedicated Azure data disk at /opt/shlink-data/data/database.sqlite. The disk is captured into the image and re provisioned on every VM, so the data tier stays independent of the operating system disk.

Back up the database with a consistent copy:
sudo sqlite3 /opt/shlink-data/data/database.sqlite ".backup '/tmp/shlink-backup.sqlite'"
For a complete point in time backup of the data tier, create an Azure managed disk snapshot of the data disk from the Azure portal or the Azure CLI. To restore, stop the web tier, replace the database file, and start the web tier again.
Step 13: Service Management
The Shlink stack is managed by systemd. The web tier is php8.4-fpm.service and nginx.service; visit processing is shlink-visits.timer. Check their state with:
systemctl is-active nginx.service php8.4-fpm.service
To restart the web tier after a configuration change:
sudo systemctl restart php8.4-fpm nginx
Support
This image is supported by cloudimg. For assistance with deployment, custom domains, REST API integration, analytics, or database administration, contact cloudimg support 24 hours a day, 7 days a week by email and chat.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.