Applications Azure

Slink on Ubuntu 24.04 on Azure User Guide

| Product: Slink on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of Slink on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Slink is an open source, self hosted image sharing and upload server. It gives you a private drop in replacement for public image hosts: users upload images through a clean browser interface, each image gets a shareable link, and you keep the files and the metadata on infrastructure you control. It pairs a Symfony REST API with a modern SvelteKit browser client, and stores images and data locally with SQLite by default.

The cloudimg image ships the free and open source, AGPL-3.0 licensed Slink server, run the officially supported way as the upstream container pinned by image digest. The image is captured into the VM, so your instance starts in seconds. Nothing here ships with a known secret: Slink generates a unique application secret and JWT signing keypair for each VM on first boot, and this image seeds a per instance admin account with a random password, before the service is reachable. New account sign ups require administrator approval and anonymous uploads are disabled, so the appliance is private by default. Backed by 24/7 cloudimg support.

Slink is a trademark of its respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by it. It ships the free and open source AGPL-3.0 licensed self hosted software, unmodified.

The docker, slink-firstboot, slink, slink-postboot and nginx services all active, and the Slink container running and healthy, published to the loopback interface on port 3000

What is included:

  • Slink server v1.12.3 (the AGPL-3.0 licensed Symfony API and SvelteKit web client), pinned by image digest
  • A SQLite application database, created empty on first boot and stored on a persistent volume
  • Docker Engine with the application published to the loopback interface only, fronted by nginx on port 80
  • slink.service, slink-firstboot.service, slink-postboot.service and nginx.service as systemd units, enabled and active on boot
  • A unique application secret and JWT signing keypair generated by the app per VM on first boot, plus a per instance admin account with a random password seeded automatically
  • Secure defaults: new account sign ups require administrator approval, anonymous guest uploads are disabled, and EXIF metadata is stripped on upload
  • No default login, no shipped secret and an empty database on first boot
  • Ubuntu 24.04 LTS base with latest security patches applied at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • Active Azure subscription, SSH public key, VNet + subnet in target region
  • Subscription to the Slink listing on Azure Marketplace

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a team or an individual. For heavier upload volumes or many concurrent users use Standard_D2s_v5 or larger. NSG inbound: allow 22/tcp from your management network and 80/tcp for the web client from the networks that use it.

Step 1: Deploy from the Azure Portal

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Slink by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create.

Step 2: Deploy from the Azure CLI

RG="slink-prod"; LOCATION="eastus"; VM_NAME="slink-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/slink-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name slink-vnet --address-prefix 10.100.0.0/16 --subnet-name slink-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name slink-nsg
az network nsg rule create -g "$RG" --nsg-name slink-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name slink-nsg --name allow-http --priority 110 \
  --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name slink-vnet --subnet slink-subnet --nsg slink-nsg --public-ip-sku Standard

Step 3: Connect to your VM

ssh azureuser@<vm-ip>

Step 4: Confirm the services are running

Slink runs as one container under slink.service, fronted by nginx. Confirm the services are active and see the container. nginx listens on :80; the application is published to 127.0.0.1 only:

sudo systemctl is-active docker slink-firstboot slink slink-postboot nginx
sudo docker ps

You will see the services report active and the container running (healthy). The application (127.0.0.1:3000) is bound only to the loopback interface; nginx on :80 is the single public front door, and the SvelteKit client proxies its API calls to the PHP backend inside the container.

Step 5: Read the per instance credentials

Slink generates a unique application secret and JWT signing keypair for this VM on first boot, and this image seeds a per instance admin account with a random password, before the app was reachable, written to a root only file. Read them:

sudo cat /root/slink-credentials.txt

The file (mode 0600 root:root) holds ADMIN_EMAIL and ADMIN_USERNAME (either can be used to sign in), ADMIN_PASSWORD (the random per instance password) and WEB_URL. None of these ship in the image; every value is unique to this VM, so no two instances share a credential and there is no default login to change.

The slink-credentials.txt file at mode 0600 root root with the per VM admin username, email and password, the password redacted, and a note that the secrets are generated uniquely on first boot with admin approval required and guest uploads disabled

Step 6: Verify the security model

The web client is reachable without authentication, but every protected API endpoint requires a bearer token. Confirm that the web client loads, that an unauthenticated request to a protected endpoint is rejected with 401, and that the per instance admin credential authenticates a real call:

ADMIN_EMAIL=$(sudo grep '^ADMIN_EMAIL=' /root/slink-credentials.txt | cut -d= -f2-)
ADMIN_PASSWORD=$(sudo grep '^ADMIN_PASSWORD=' /root/slink-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'web client   (no auth):    %{http_code}\n' -L http://localhost/
curl -s -o /dev/null -w 'user api     (no token):   %{http_code}\n' -H 'Accept: application/json' http://localhost/api/user
TOKEN=$(curl -s -X POST http://localhost/api/auth/login \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d "{\"username\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
curl -s -o /dev/null -w 'user api     (with token): %{http_code}\n' \
  -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' http://localhost/api/user

The web client returns 200, the protected user endpoint is rejected with 401 for no token, and the same call with the per instance admin bearer token returns 200. This is the security model: the API is gated by a JWT you obtain by signing in with the per instance admin credential.

The Slink first boot security configuration showing public registration enabled, new account approval required, anonymous guest uploads disabled and EXIF metadata stripping enabled, with the per VM ORIGIN resolved to the instance address

The same round trip is bundled as a single script on the image, which the build and smoke tests run to prove the credential works end to end:

sudo /usr/local/sbin/slink-roundtrip.sh

The bundled round trip script reporting OK: the web client and backend are live, no and wrong tokens are rejected with 401, and the per instance admin credential authenticates a real API call

Step 7: Open the web client and sign in

Browse to http://<vm-ip>/ to reach the Slink web client. Select Sign In and enter the ADMIN_EMAIL (or ADMIN_USERNAME) and ADMIN_PASSWORD from Step 5. New users can request an account with Sign Up, but each request must be approved by an administrator before it can be used (see Step 10).

The Slink Sign In page, with the Email or Username and Password fields and the Sign In button, and a Sign Up prompt for creating a new account

Step 8: Upload an image

Select Upload to open the drop zone. Drag an image onto it or click to browse from your device. Slink accepts JPEG, PNG, GIF, WebP, AVIF, SVG and more, up to the configured maximum size. Uploads default to Private, and you can attach tags or add them to a collection before uploading.

The Slink upload page with a drop your images here zone, the supported formats JPEG PNG GIF WebP AVIF SVG, a maximum size of 15 MB, and Private, Tags and Collections controls

Step 9: View your image and copy its share link

After the upload completes, Slink opens the image details page: your image is displayed with its dimensions, format and size, and a ready to use share link you can copy. You can resize the shared version, convert the format (Original, JPG, WebP or AVIF), download the file, add a description, and set an expiry or a password on the share.

The Slink image details page showing an uploaded sample image rendered at 1280 by 860 as a PNG, with resize and format controls and a Share section containing a copyable link to the image

Step 10: Administer users and settings

As the admin you have an Administration area with a dashboard, user management and settings. Open Settings to configure image uploads and sharing, storage, and the security policies (user registration, access control and authentication), or Users to approve pending sign ups and manage accounts.

The Slink admin Settings page with cards for Image Settings, Storage Configuration, Security Settings for user registration and access control, and Single Sign On for OIDC identity providers

Step 11: Manage registration and approval

By default, users can request accounts with Sign Up but every request must be approved by an administrator before it becomes active, and anonymous guest uploads are disabled. Approve or reject pending users under Administration → Users. You can change the registration, approval and guest upload policies under Administration → Settings → Security Settings. These knobs are also set as environment defaults in /etc/slink/compose.yaml; if you change them there, apply the change with:

sudo systemctl restart slink

Step 12: Call the API from your own machine

Every feature of the web client is backed by the REST API, which you can call directly. Obtain a token by signing in, then call a protected endpoint with the VM address:

TOKEN=$(curl -s -X POST http://<vm-ip>/api/auth/login \
  -H 'Content-Type: application/json' -H 'Accept: application/json' \
  -d '{"username":"<ADMIN_EMAIL>","password":"<ADMIN_PASSWORD>"}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')
curl -s -H "Authorization: Bearer $TOKEN" -H 'Accept: application/json' "http://<vm-ip>/api/user"

The login returns a JWT bearer token whose payload identifies the admin (ROLE_ADMIN); pass it as an Authorization: Bearer header to reach protected endpoints.

Step 13: Server components

Component Version / Detail
Application Slink v1.12.3 (Symfony API + SvelteKit client, pinned by image digest)
Front door nginx on :80 proxying to the app on 127.0.0.1:3000
Application database SQLite (created empty on first boot, on a persistent volume)
Image storage local filesystem on a persistent volume (EXIF stripped on upload)
Orchestration Docker Compose under slink.service
Application secret + keys per instance, generated by the app on first boot
Admin account per instance random password, seeded first boot into /root/slink-credentials.txt
Operating system Ubuntu 24.04 LTS (patched at build)
License AGPL-3.0 (Slink)

Step 14: Managing the service

sudo systemctl status slink --no-pager | head -12
sudo docker compose -f /etc/slink/compose.yaml logs --tail 40 slink

Restart the stack with sudo systemctl restart slink, follow the logs live with sudo docker compose -f /etc/slink/compose.yaml logs -f slink, and view configuration in /etc/slink/slink.env and /etc/slink/compose.yaml. After changing the environment file, restart the service to apply it.

Step 15: Use your own domain and HTTPS (production)

The image serves the web client over plain HTTP on port 80, which is convenient behind a load balancer or private network. For production you should terminate TLS in front of the VM so credentials travel encrypted:

  • Front the VM with Azure Application Gateway, a load balancer with a managed certificate, or a CDN, and forward to nginx on port 80.
  • Or install your own certificate: add a TLS server block to /etc/nginx/sites-available/slink referencing your certificate and key, open 443/tcp on the NSG, then sudo systemctl reload nginx.
  • Point a DNS name you control at the VM public IP. Because the web client reads its public origin (ORIGIN) at first boot from the resolved public address, use a stable public IP, or set ORIGIN in /etc/slink/slink.env to your domain and restart the service when using a custom domain.

Step 16: Security recommendations

  • Restrict the NSG. Allow TCP 80 (and 22 for admin) only from the networks that use the app.
  • Terminate TLS in front of the app (Step 15) so the admin password and tokens are encrypted in transit.
  • Rotate the seeded admin password. Sign in and change it, and keep registration behind admin approval (the default).
  • Keep the app private. The container is bound to loopback and fronted by nginx; keep it that way and never expose the container port directly.
  • Keep the OS patched. Unattended security upgrades remain enabled on the running VM.

Step 17: Support and Licensing

Slink is distributed under the GNU Affero General Public License v3.0 (AGPL-3.0). This cloudimg image bundles the unmodified official open source release; cloudimg provides the packaging, the nginx front door, the per instance admin generation, the secure by default configuration, the paired deploy guide, and 24/7 support with a guaranteed 24 hour response SLA. Slink is an independent open source project and this image is not affiliated with or endorsed by it.

Deploy on Azure

Launch Slink on Ubuntu 24.04 LTS by cloudimg from the Azure Marketplace and follow this guide to a working self hosted image sharing server in minutes.