Applications Azure

Immich on Ubuntu 24.04 on Azure User Guide

| Product: Immich on Ubuntu 24.04 LTS on Azure

Overview

Immich is a self-hosted photo and video management platform - a private alternative to commercial cloud photo services. You upload your photos and videos, browse them on a fast timeline, organise them into albums, search and share them, and keep everything in sync from the Immich mobile apps. The cloudimg image installs the official Immich self-host Docker Compose stack, pinned to v3.1.0: the immich-server (the API and web UI), a PostgreSQL 14 database with the VectorChord / pgvecto-rs vector extension, and a redis (Valkey) cache. A host nginx allowlist reverse-proxy publishes the app on port 80, and the database and cache stay on the internal Docker network only.

Immich has no default administrator - the first account registered on a new instance becomes the admin. On a public VM that is a trap: an unauthenticated visitor could seize a fresh machine by registering first. The cloudimg image closes it. On the first boot of every VM, before the site is reachable, a fresh per-VM admin is seeded through the Immich admin sign-up API, the database password is rotated and the database is initialised clean (which regenerates all of Immich's session material), and the one unique admin password is written to a root-only file. Backed by 24/7 cloudimg support.

What is included:

  • The official Immich v3.1.0 self-host stack running under Docker (the immich-server, a PostgreSQL 14 + VectorChord database and a Valkey redis), pinned so it never silently upgrades
  • The web UI and API published on port 80 through an nginx allowlist reverse-proxy (server_tokens off, absolute_redirect off, the .env and compose file return 404)
  • A per-VM admin account seeded on first boot - a unique password recorded in a root-only file - before the site is reachable, so the first-registration-becomes-admin trap is closed on every VM
  • The PostgreSQL password rotated and the database re-initialised clean on first boot, so no two VMs share a database or session secret
  • The whole stack managed as one immich.service systemd unit, gated on the first-boot marker, plus nginx.service and docker.service, all enabled
  • PostgreSQL and Redis bound to the internal Docker network only - just 22/tcp (SSH) and 80/tcp (the Immich UI) are exposed
  • Machine learning (smart search, face recognition) shipped switched off so the appliance runs comfortably on a small VM, with clear steps to enable it on a larger one
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) comfortably runs the core stack (server + database + cache) with machine learning off. If you want Immich's machine-learning features (smart search and face recognition), launch on a larger size such as Standard_B4ms (see Step 10). NSG inbound: allow 22/tcp from your management network and 80/tcp from the clients that will use Immich. The app serves plain HTTP; for production, put it behind your own domain and TLS.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Immich 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), then add 80 after deployment. Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name immich \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name immich --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the stack is running

Immich runs as a Docker Compose stack managed by a single systemd unit. On first boot the stack rotates its database password, re-initialises on a clean database, seeds the per-VM admin and starts; the multi-container stack can take a minute or two to become fully healthy after the VM is created.

systemctl is-active immich.service

It reports active. You can list the running containers with:

sudo docker compose -f /var/lib/immich/docker-compose.yml ps

Immich Compose stack running under Docker - the immich-server, a PostgreSQL with VectorChord database and a Valkey redis, all healthy, managed as one immich.service systemd unit

The whole stack is managed as one systemd unit - use sudo systemctl status immich and sudo systemctl restart immich to control every container together.

Step 5 - Retrieve your per-VM admin credentials

The admin password is generated uniquely on the first boot of your VM and written to a root-only file. Confirm the file exists (it is 0600, root-only):

sudo ls -l /root/immich-credentials.txt

Then read it to get your credentials:

sudo cat /root/immich-credentials.txt

The file contains immich.url (the address to browse to), immich.admin.email and IMMICH_ADMIN_PASSWORD (for the web UI). Store them somewhere safe. The first-boot service that seeded them is a one-shot unit you can confirm ran:

systemctl is-active immich-firstboot.service

Immich first-boot secret rotation - the credentials file exists as a root-only 0600 file and the first-boot service is active, proving the per-VM admin was seeded before the site was reachable

Step 6 - Confirm the endpoints are healthy

The Immich UI answers on port 80 through the nginx reverse-proxy:

curl -s -o /dev/null -w 'UI (nginx :80) -> HTTP %{http_code}\n' http://localhost/

It returns HTTP 200. The Immich server's health endpoint answers pong:

curl -s http://localhost/api/server/ping

You can confirm which ports are published - PostgreSQL (5432) and Redis (6379) are deliberately not among them, they stay on the internal Docker network:

sudo ss -tlnH | awk '{print $4}' | sort -u

Immich endpoints healthy - the UI returns HTTP 200 through nginx and the server health check returns pong, while only SSH and the UI are exposed; PostgreSQL and Redis stay on the internal Docker network

Step 7 - Confirm the pinned release

The images are pinned to Immich v3.1.0 (with the database and cache images digest-pinned) so the appliance never silently upgrades:

sudo docker compose -f /var/lib/immich/docker-compose.yml images

Immich pinned release - the immich-server is pinned to v3.1.0 and the PostgreSQL/VectorChord and Valkey images are digest-pinned, so the appliance always runs exactly the release you launched

Step 8 - Sign in to the web UI

In a browser, go to http://<vm-public-ip>/. You are greeted by the Immich login page. Sign in with the immich.admin.email and IMMICH_ADMIN_PASSWORD from Step 5. Because the admin was already seeded on first boot, there is no "register" step for a stranger to hijack - you land straight on the login form.

The Immich login page served on port 80 - the per-VM admin was already seeded on first boot, so a visitor signs in rather than registering as the first admin

Step 9 - Upload your first photos

Select Upload (top right) and choose some photos or videos, or install an Immich mobile app and point it at http://<vm-public-ip>/ to back up your camera roll automatically. Uploaded media appears on the timeline immediately, grouped by date.

The Immich Photos timeline rendering uploaded photos, grouped by day, with the search bar and the Photos, Explore, Map and Sharing navigation

Group photos into albums from the Albums section - create an album, add assets to it, and share it with a link or another user.

The Immich Albums view showing an album of uploaded photos, ready to share

Step 10 - Manage users and enable machine learning (optional)

As the admin you manage users and server settings from Administration. The image ships with exactly one account - your per-VM admin - and Immich only creates further users when you invite them, so there is no open sign-up.

Immich Administration - User Management shows the single per-VM cloudimg admin account, and the footer confirms the server is online on v3.1.0

Machine learning (smart search and face recognition) ships disabled so the appliance fits a small VM. To enable it, launch the image on a larger VM (Standard_B4ms or bigger), then bring the machine-learning container up and turn the feature on:

cd /var/lib/immich
sudo docker compose --profile ml up -d

Then, in the web UI, go to Administration -> Settings -> Machine Learning Settings and enable it. Immich will begin generating smart-search embeddings and detecting faces on your library.

Support

Every cloudimg image is backed by 24/7 support and a deploy guide tested against the exact build. If you need help, contact cloudimg support.