Shlink
Overview
Shlink is a self-hosted URL shortener that gives you complete ownership of your short links, their data and their analytics. This SecureAnyCloud image runs Shlink 5.1.0 behind nginx with PHP 8.4 FPM on a hardened Ubuntu 24.04 LTS base, patched at build time.
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. The web client's server entry is wired to the key automatically.
On first boot, the image reads the VM address from Azure instance metadata and uses it as Shlink's default short domain. Generated short URLs therefore use the address that customers reach the VM on. To serve short links on your own branded domain, set a custom domain as described in Step 10.
What you get:
- 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 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. The Azure CLI is required only if you deploy from the command line.
Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point. Size up for higher redirect volumes.
Configure these network security group inbound rules: allow 22/tcp from your management network, and allow 80/tcp (and 443/tcp once you add TLS) from the networks that will use your short links.
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 SecureAnyCloud. 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, set 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. Select Review + create. First-boot initialisation completes about a minute after the VM reaches the Running state.
Launch from the Azure CLI
This command creates a VM from the SecureAnyCloud Shlink image. Replace the angle-bracket values with your own. The image reference is shown on the Marketplace offer page.
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:shlink-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-resource-group> \
--name shlink-01 \
--image sac1647283583153:shlink-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values <path-to-your-public-key> \
--public-ip-sku Standard \
--nsg-rule SSHWhen 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.
Connect and Retrieve the API Key
Connect over SSH as azureuser, using the VM's public IP address:
ssh azureuser@<public-ip>Read the generated API key. It is stored in a root-only file, so use sudo:
sudo cat /root/shlink-credentials.txtThe file contains the web client URL, the REST API base URL, and the per-VM API key:
Confirm the Service Is Healthy
Shlink exposes an unauthenticated health endpoint. Confirm that it reports pass and the expected version, and that nginx and PHP FPM are active:
systemctl is-active nginx php8.4-fpmcurl -s http://127.0.0.1/rest/healthA healthy VM returns a JSON document containing "status":"pass" and "version":"5.1.0".
Open the Shlink Web Client
Browse to http://<public-ip>/ in a web browser. The Shlink web client loads and connects to this VM automatically using the generated API key, so no manual server setup 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.
Create a Short URL
Open Create short URL in the web client and paste the long URL you want to shorten into URL to be shortened. Optionally set a title, custom slug, tags or access limits, then 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. This command reads the key from the credentials file and creates a short URL for https://secureanycloud.com:
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://secureanycloud.com","findIfExists":true}' \
http://127.0.0.1/rest/v3/short-urlsThe response is a JSON document describing the new short URL, including its shortCode and full shortUrl.
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-urlsRequests without a valid key are rejected. This request omits the header and returns HTTP 401, which confirms that the API is protected:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/rest/v3/short-urlsRead 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:
systemctl status shlink-visits.timer --no-pagerGeolocation requires a free MaxMind GeoLite2 license key. Without one, visits are still recorded and analysed by time and context, and 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.
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:listTo 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. Shlink shows the full key only once, at creation:
sudo -u www-data php8.4 /opt/shlink/bin/cli api-key:generate --name=my-application
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. Set 'DEFAULT_DOMAIN' to your domain, and set 'IS_HTTPS_ENABLED' to true once you have TLS in place. Restart the service afterwards with sudo systemctl restart php8.4-fpm nginx.
Enable HTTPS
For production use, terminate TLS in front of Shlink. The simplest approach on a single VM is Let's Encrypt with Certbot. Certbot prompts interactively for an email address and agreement to the terms of service, so 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.
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.
Service Management
systemd manages the Shlink stack. The web tier is php8.4-fpm.service and nginx.service, and visit processing is shlink-visits.timer. Check their state:
systemctl is-active nginx.service php8.4-fpm.serviceTo restart the web tier after a configuration change:
sudo systemctl restart php8.4-fpm nginx
Support
SecureAnyCloud supports this image. For help with deployment, custom domains, REST API integration, analytics or database administration, contact SecureAnyCloud 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.
Deploy on Azure
Launch Shlink on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
This image runs Shlink, the self-hosted URL shortener, behind nginx with PHP FPM 8.4. Short URLs, their visits and all analytics are stored in a SQLite database on a dedicated, independently resizable EBS data volume 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 instance and is pre-connected to the local REST API.
The Shlink REST API and short URL redirects are served at the instance root, with the API under the /rest path. The web client is served at the instance root as well, so browsing to the instance address opens the management console. A systemd timer runs Shlink's visit processing every fifteen minutes.
A per-instance administrator API key is generated on the first boot of every deployed instance. Two instances launched from the same Amazon Machine 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. The web client's server entry is wired to the key automatically.
On first boot, the image reads the instance's public address from EC2 instance metadata and uses it as Shlink's default short domain. Generated short URLs therefore use the address that customers reach the instance on. To serve short links on your own branded domain, set a custom domain as described in Step 10.
Prerequisites
Before you deploy this image, you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound ports 80 and 443 from the networks that will use your short links
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Shlink URL Shortener. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger. Choose your EC2 key pair under Key pair (login).
Under Network settings, select your VPC and subnet. Create or select a security group that allows inbound port 22 from your management network and inbound ports 80 and 443 from the networks that will use your short links. Leave the root volume and the attached data volume at their default sizes or larger.
Select Launch instance. First-boot initialisation takes approximately one minute after the instance state becomes Running and the status checks pass.
Launch the Instance from the AWS CLI
This command launches an instance from the SecureAnyCloud Shlink Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22, 80 and 443 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":12,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=shlink-01}]'On success, the command prints a JSON document. Note the instance ID, then retrieve the instance's public address when it is running, with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and Retrieve the API Key
Connect over SSH with the key pair you selected and the public IP address from Step 2. The SSH login user depends on the operating system of the AMI variant you launched:
AMI variant SSH login user
Shlink 5.1.0 on Ubuntu 24.04 ubuntu
Read the generated API key. It is stored in a root-only file, so use sudo:
sudo cat /root/shlink-credentials.txtThe file contains the web client URL, the REST API base URL, and the per-instance API key:
shlink.web.client=http://<your-instance-address>/ shlink.api.base=http://<your-instance-address>/rest shlink.api.key=8f3c9a21-7d4e-4b6a-9c2f-1e5d8a0b3f47Confirm the Service Is Healthy
Shlink exposes an unauthenticated health endpoint. From the instance, confirm that it reports pass and the expected version:
curl -s http://127.0.0.1/rest/healthA healthy instance returns a JSON document containing "status":"pass" and "version":"5.1.0".
Open the Shlink Web Client
Browse to http://<your-instance-address>/ in a web browser. The Shlink web client loads and connects to this instance automatically using the generated API key, so no manual server setup is required.
The Overview page shows your 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.
Create a Short URL
Open Create short URL in the web client and paste the long URL you want to shorten into URL to be shortened. Optionally set a title, custom slug, tags or access limits, then 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. This command reads the key from the credentials file and creates a short URL for https://secureanycloud.com:
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://secureanycloud.com","findIfExists":true}' \
http://127.0.0.1/rest/v3/short-urlsThe response is a JSON document describing the new short URL, including its shortCode and full shortUrl.
List Short URLs Through 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-urlsRequests without a valid key are rejected. This request omits the header and returns HTTP 401, which confirms that the API is protected:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/rest/v3/short-urlsRead 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:
systemctl status shlink-visits.timer --no-pagerGeolocation requires a free MaxMind GeoLite2 license key. Without one, visits are still recorded and analysed by time and context, and 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.
Manage API Keys
Shlink supports multiple API keys with different roles. List the keys on the instance:
sudo -u www-data php8.4 /opt/shlink/bin/cli api-key:listTo 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. Shlink shows the full key only once, at creation:
sudo -u www-data php8.4 /opt/shlink/bin/cli api-key:generate --name=my-application
Use a Custom Short Domain
By default, short URLs use the instance's address. To serve short links on your own domain, point a DNS record at the instance. Then edit /opt/shlink/config/params/generated_config.php. Set 'DEFAULT_DOMAIN' to your domain, and set 'IS_HTTPS_ENABLED' to true once you have TLS in place. Restart the service afterwards with sudo systemctl restart php8.4-fpm nginx.
Enable HTTPS
For production use, terminate TLS in front of Shlink. The simplest approach on a single instance is Let's Encrypt with Certbot. Install Certbot and request a certificate for your domain, then set 'IS_HTTPS_ENABLED' => true in the configuration file. Certbot prompts interactively for an email address and agreement to the terms of service, so 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, reload nginx with sudo systemctl reload nginx.
Backups
All Shlink data lives in the SQLite database on the data volume at /opt/shlink-data/data/database.sqlite. Back it up 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 EBS snapshot of the data volume from the EC2 console or the AWS CLI. To restore, stop the web tier, replace the database file, and start the web tier again.
Service Management
systemd manages the Shlink stack. The web tier is php8.4-fpm.service and nginx.service, and visit processing is shlink-visits.timer. Check their state:
systemctl is-active nginx.service php8.4-fpm.serviceTo restart the web tier after a configuration change:
sudo systemctl restart php8.4-fpm nginx
Support
SecureAnyCloud supports this image. For help with deployment, custom domains, REST API integration, analytics or database administration, contact SecureAnyCloud 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.
Deploy on AWS
Launch Shlink URL Shortener on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com