How To Install Immich on Ubuntu 26.04 LTS

Install Immich on Ubuntu 26.04

Every sysadmin eventually gets the same request from a friend or family member: “Can you set up something so I stop paying for cloud photo storage?” For years, the honest answer was “not really, unless you want to babysit a half-broken PHP app.” That changed once Immich matured into a genuinely production-ready alternative to Google Photos, and with Ubuntu 26.04 LTS “Resolute Raccoon” now shipping kernel 7.0, Docker 29, and PostgreSQL 18 out of the box, the underlying platform finally caught up to what a modern self-hosted photo server actually needs.

This guide walks through installing Immich on a fresh Ubuntu 26.04 LTS server, not a toy VM with two vCPUs and a prayer, but a configuration that will actually hold up when someone dumps 40,000 photos and four years of iPhone video into it overnight. That scenario is not hypothetical. It happens constantly during the first migration week, and it’s exactly when undersized deployments start throwing OOM errors or grinding the machine-learning worker to a halt.

Immich handles facial recognition, semantic search, live photos, RAW formats, and mobile auto-backup, which means it’s doing considerably more work than a static file server. It runs as a stack of containers: a Postgres database with the pgvecto.rs extension for vector search, Redis for job queuing, a machine-learning microservice, and the main API/server process, all sitting behind whatever reverse proxy you choose to front it with. Getting this right on Ubuntu 26.04 LTS involves a few platform-specific quirks worth knowing before you start, particularly around the switch to sudo-rs and the tightened default firewall behavior in this release.

By the end of this walkthrough, you’ll have a working Immich instance reachable over HTTPS, backed by systemd-managed Docker Compose, with sane resource limits, automatic updates disabled (on purpose, more on that later), and a firewall configuration that doesn’t leave your database port hanging open to the internet. We’ll also cover hardware transcoding, because nobody wants their CPU pegged at 100% every time a phone uploads a 4K video.

Why Ubuntu 26.04 LTS Is a Solid Base for Immich

Ubuntu 26.04 LTS brings Linux kernel 7.0, which matters more than it might seem for this particular workload. Immich’s hardware transcoding features, especially VAAPI and Intel Quick Sync paths, depend heavily on kernel-level driver support, and older kernels shipped with Ubuntu 22.04 caused real headaches with 11th-gen Intel CPUs needing Low-Power mode workarounds. That entire class of problem is largely gone on 26.04.

The release also ships Docker 29 in the default repositories territory, though most admins will still prefer installing directly from Docker’s own APT repo to stay current with security patches faster than Canonical’s cadence allows. PostgreSQL 18 is available system-wide too, but don’t be tempted to use it directly. Immich needs the pgvecto.rs or pgvector extension bundled into its own container image, and mixing that with a host-level Postgres install is a common mistake that leads to version mismatch errors nobody enjoys debugging at 11 PM.

One more thing worth flagging: 26.04 defaults to sudo-rs instead of the traditional sudo binary. Functionally it behaves the same for almost everything in this guide, but if you’re scripting automated deployments, double-check any sudo flag usage against the sudo-rs manpage, since a handful of edge-case flags aren’t yet at parity.

Prerequisites and Server Sizing

Before touching a terminal, get the sizing right. Immich’s official minimums are 2 CPU cores and 6 GB of RAM, but that’s genuinely a bare-minimum figure for a small personal library. In practice, for a household or small team library in the tens of thousands of photos:

  • CPU: 4 cores minimum, 8 cores/16 threads if you expect concurrent video transcoding and machine-learning jobs running simultaneously.
  • RAM: 8 GB minimum, 16 GB comfortable, 32 GB if multiple users upload simultaneously or you’re running facial recognition against a large backlog.
  • Storage: A fast NVMe SSD for the Postgres database and Redis, and separate storage (can be an HDD array, NAS mount, or cloud-backed volume) for the actual photo/video library. Never point the database volume at network storage; it’s explicitly unsupported and will eventually corrupt under load.
  • Architecture: amd64 or arm64. Note that since Immich v3, the amd64 machine-learning container requires x86-64-v2 instruction set support, so ancient CPUs (pre-2010 Nehalem-era or earlier) may fail to run the ML service at all.

You also need a domain name if you want proper HTTPS (Let’s Encrypt won’t issue for bare IPs), and root or sudo access on a fresh Ubuntu 26.04 LTS installation.

Step 1: Update the System and Prep the Environment

Start clean. Skipping this step and running into a weird apt dependency conflict three steps later is a rite of passage nobody needs to repeat.

sudo apt update && sudo apt full-upgrade -y
sudo reboot

After the reboot, install a few utilities that make life easier later:

sudo apt install -y curl wget git ufw fail2ban htop

Create a dedicated non-root user if you haven’t already. Running Docker as root indefinitely is a habit worth breaking early:

sudo adduser immichadmin
sudo usermod -aG sudo immichadmin
su - immichadmin

Step 2: Install Docker Engine and Docker Compose

Ubuntu’s default repos include Docker packages now, but the official Docker repository stays ahead on patches and is what most production environments actually use. Add it properly instead of relying on the snap version, which has caused mount and networking oddities for Immich users in the past.

# Remove any old/conflicting packages first
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt remove $pkg; done

sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Add your user to the docker group so you’re not typing sudo before every command:

sudo usermod -aG docker $USER
newgrp docker

Verify everything landed correctly:

docker --version
docker compose version

Note the space between docker and compose. The hyphenated docker-compose binary is deprecated and shouldn’t be used on a fresh 26.04 install; the plugin-based syntax is the only one worth learning at this point.

Step 3: Download and Configure Immich

Create a dedicated directory structure. Keeping this outside your home directory under /opt makes backup scripting and permission management considerably cleaner in the long run.

sudo mkdir -p /opt/immich
sudo chown $USER:$USER /opt/immich
mkdir -p /opt/immich/library
cd /opt/immich

Pull the current release’s Compose file and environment template directly from the project’s GitHub releases:

wget -O docker-compose.yml https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml
wget -O .env https://github.com/immich-app/immich/releases/latest/download/example.env

Now edit the .env file. This is where most people rush and where most mistakes originate:

nano .env

Key values to set carefully:

UPLOAD_LOCATION=/opt/immich/library
DB_DATA_LOCATION=/opt/immich/postgres
DB_PASSWORD=<generate-a-strong-random-password>
IMMICH_VERSION=release
TZ=Asia/Jakarta

That UPLOAD_LOCATION should point somewhere with genuine capacity, ideally on a separate mount from your OS disk. If you’re mounting an external drive or a NAS share for the actual photo library (not the database, that stays local), verify it’s mounted persistently in /etc/fstab before proceeding, or you’ll get a nasty surprise the first time the server reboots and Immich starts writing to an empty directory instead of your mount point.

Generate a strong database password rather than leaving the placeholder:

openssl rand -base64 24

Paste that into DB_PASSWORD. Never leave default credentials on anything internet-facing, even behind a firewall. Defense in depth isn’t optional anymore, it’s table stakes.

Step 4: Launch the Stack

With the environment file squared away, bring the containers up:

docker compose up -d

Watch the logs on first boot, since the database migrations and initial container pulls take a minute or two:

docker compose logs -f

Once the immich-server container reports it’s listening, open a browser and navigate to:

http://your-server-ip:2283

You’ll land on the admin account creation screen. Set a strong password here too; this account has full administrative control over the entire library and user base.

Install Immich on Ubuntu 26.04

Step 5: Reverse Proxy and HTTPS with Nginx

Exposing port 2283 directly to the internet is asking for trouble. Put Nginx in front of it and terminate TLS properly.

sudo apt install -y nginx certbot python3-certbot-nginx

Create a server block:

sudo nano /etc/nginx/sites-available/immich
server {
    listen 80;
    server_name photos.yourdomain.com;

    client_max_body_size 50G;
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;

    location / {
        proxy_pass http://127.0.0.1:2283;
        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;
    }
}

That client_max_body_size 50G isn’t excessive paranoia. Immich supports large video uploads, and the default Nginx body size limit will silently reject large mobile backups with a 413 error that’s genuinely confusing to diagnose the first time you see it.

Enable the site and obtain a certificate:

sudo ln -s /etc/nginx/sites-available/immich /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d photos.yourdomain.com

Firewall and Security Hardening

Ubuntu 26.04 LTS ships with tighter default firewall assumptions than earlier releases, but you still need to configure UFW explicitly. Docker manages its own iptables rules under the hood, which sometimes conflicts with UFW in confusing ways if not handled deliberately.

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verbose

Crucially, do not open port 2283 or 5432 (Postgres) directly through UFW. Those should only be reachable via localhost through the reverse proxy. Docker’s default bridge network already isolates the Postgres and Redis containers from the outside world unless you’ve explicitly published their ports, which the standard Compose file doesn’t do.

Additional hardening steps worth doing on any internet-facing server:

  • Disable password-based SSH login and enforce key-based auth only.
  • Configure fail2ban with a jail targeting Nginx auth failures if you’re not using Immich’s own OAuth integration.
  • Set DB_PASSWORD rotation reminders; treat it like any other production credential.
  • Keep the .env file permissions locked down: chmod 600 .env.

Hardware Transcoding: Don’t Skip This

If your server does any real volume of video uploads, software transcoding alone will melt your CPU. Immich supports NVENC (NVIDIA), Quick Sync (Intel), and VAAPI acceleration.

For Intel Quick Sync on a modern CPU, download the hardware acceleration Compose override:

wget -O hwaccel.transcoding.yml https://github.com/immich-app/immich/releases/latest/download/hwaccel.transcoding.yml

Edit docker-compose.yml, find the immich-server service, and uncomment the extends block pointing to this file, setting the backend to qsv or vaapi depending on your hardware. Redeploy:

docker compose up -d

Then, inside the Immich admin panel under Video Transcoding Settings, switch the hardware acceleration dropdown to match. One quirk worth knowing: on certain older Intel chips (Jasper Lake, Elkhart Lake), you also need to set the Constant Quality mode to CQP, or transcoding jobs will fail silently and pile up in the queue without any obvious error in the logs.

Troubleshooting Common Issues

Container stuck restarting on first boot

Almost always a permissions problem on UPLOAD_LOCATION or DB_DATA_LOCATION. Check ownership matches the user Docker is running as:

docker compose logs immich-server | tail -50
sudo chown -R 999:999 /opt/immich/postgres

Machine learning jobs stuck at 0% forever

This is often a memory ceiling issue. The ML container needs headroom beyond what the main server uses; check docker stats during a facial recognition job and bump RAM if it’s maxing out.

413 Request Entity Too Large on mobile upload

Nginx’s client_max_body_size wasn’t set high enough, or you forgot to reload Nginx after editing the config. Confirm with sudo nginx -t before reloading.

Mobile app can’t connect over HTTPS

Usually a certificate chain issue or a firewall rule blocking port 443. Test externally with curl -I https://photos.yourdomain.com from a different network to rule out local DNS caching.

Database won’t start after a host reboot

Check that your mount points in /etc/fstab are correct, especially if DB_DATA_LOCATION sits on a separate disk. A missing mount at boot means Docker creates an empty directory in its place, and Postgres will refuse to start against what looks like a corrupted data directory.

Backup Strategy and Long-Term Maintenance

Photos are the kind of data people notice missing only after it’s gone. Set up automated backups covering both the Postgres database dump and the actual library files.

docker exec -t immich_postgres pg_dumpall -c -U postgres > /opt/backups/immich-db-$(date +%F).sql

Pair this with an rsync or restic job targeting your library directory, ideally to offsite or object storage. Test the restore process at least once; a backup that’s never been restored is a backup you don’t actually have.

For updates, resist the urge to auto-pull latest blindly on a production instance. Pin IMMICH_VERSION to a specific release tag, read the release notes (breaking changes do happen, particularly around database migrations), and update on a schedule you control rather than whatever cron job Watchtower decided to run at 3 AM.

Immich on Ubuntu 26.04 LTS is, frankly, one of the more satisfying self-hosting projects to run well. It rewards a little upfront care in sizing and security, and once it’s running, it just quietly works, which is exactly what you want from infrastructure nobody should have to think about twice a week.

r00t is an experienced Linux enthusiast and technical writer with a passion for open-source software. With years of hands-on experience in various Linux distributions, r00t has developed a deep understanding of the Linux ecosystem and its powerful tools. He holds certifications in SCE and has contributed to several open-source projects. r00t is dedicated to sharing her knowledge and expertise through well-researched and informative articles, helping others navigate the world of Linux with confidence.

Related Posts