Install and maintain Immich on Ubuntu
The current image installs a pinned native Immich v3.0.3 stack on Ubuntu 24.04 x86-64 with PostgreSQL, Redis, a systemd service, and Nginx on localhost port 2283.
Before you start
- Use a clean, supported Ubuntu server with root or sudo access.
- Point
app.example.comto the server before requesting a public TLS certificate. - Replace every value written as
CHANGE_MEand store the generated credentials in a password manager. - Take a snapshot before changing an existing installation.
- Ubuntu 24.04 or newer on x86-64.
- Substantial local storage for originals, thumbnails, and database backups.
- This native build has machine learning disabled, matching the current playbook.
What the AppStore installation creates
- Pinned Immich v3.0.3 source and release directories below
/opt/immich - Dedicated
immichsystem user - PostgreSQL with cube, earthdistance, pg_trgm, and vector extensions
- Redis on localhost and
immich-server.serviceon port 2283 - Media below
/var/lib/immichand Nginx with unbuffered uploads
1. Install native build dependencies
The image uses pinned Node.js 24.15.0, pnpm 11.6.0, PostgreSQL 16 with pgvector, Redis, FFmpeg, and native image-processing libraries.
sudo apt update
sudo apt install -y --no-install-recommends build-essential ca-certificates curl \
ffmpeg git jq libimage-exiftool-perl nginx openssl pkg-config postgresql \
postgresql-16-pgvector postgresql-contrib python3 qemu-guest-agent \
redis-server unzip xz-utils certbot python3-certbot-nginx ufw
sudo systemctl enable --now postgresql redis-server nginx
2. Create users, paths, and database
Generate a separate random database password and store it only in the protected environment file.
sudo useradd --system --home /opt/immich --create-home --shell /usr/sbin/nologin immich
sudo install -d -o immich -g immich -m 0750 /opt/immich/releases /opt/immich/build /var/lib/immich
sudo -u postgres createuser immich
sudo -u postgres createdb -O immich immich
sudo -u postgres psql -d immich -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
sudo -u postgres psql -d immich -c "CREATE EXTENSION IF NOT EXISTS unaccent;"
sudo -u postgres psql -d immich -c 'CREATE EXTENSION IF NOT EXISTS cube;'
sudo -u postgres psql -d immich -c 'CREATE EXTENSION IF NOT EXISTS earthdistance;'
sudo -u postgres psql -d immich -c 'CREATE EXTENSION IF NOT EXISTS pg_trgm;'
sudo -u postgres psql -d immich -c 'CREATE EXTENSION IF NOT EXISTS vector CASCADE;'
3. Install the pinned Node/pnpm toolchain and build source
The image verifies both downloaded archives, builds the server and web workspaces, and deploys the production server tree as the immich user.
curl -fL https://nodejs.org/dist/v24.15.0/node-v24.15.0-linux-x64.tar.xz -o /tmp/node-v24.15.0-linux-x64.tar.xz
printf "%s %s\n" "472655581fb851559730c48763e0c9d3bc25975c59d518003fc0849d3e4ba0f6" "/tmp/node-v24.15.0-linux-x64.tar.xz" | sha256sum --check -
sudo install -d -m 0755 /opt/node-v24.15.0-linux-x64
sudo tar -xJf /tmp/node-v24.15.0-linux-x64.tar.xz --strip-components=1 -C /opt/node-v24.15.0-linux-x64
sudo /opt/node-v24.15.0-linux-x64/bin/npm install --global pnpm@11.6.0
sudo -u immich curl -fL https://github.com/immich-app/immich/archive/refs/tags/v3.0.3.tar.gz -o /tmp/immich-v3.0.3.tar.gz
printf "%s %s\n" "a974565a1cb2871a9276e84c3f14d48f771126404cc02236bb377d556387f6fa" "/tmp/immich-v3.0.3.tar.gz" | sha256sum --check -
sudo -u immich install -d -m 0750 /opt/immich/source-3.0.3 /opt/immich/releases/3.0.3
sudo -u immich tar -xzf /tmp/immich-v3.0.3.tar.gz --strip-components=1 -C /opt/immich/source-3.0.3
sudo -u immich env HOME=/opt/immich PATH=/opt/node-v24.15.0-linux-x64/bin:/usr/bin:/bin \
pnpm --dir /opt/immich/source-3.0.3 --filter @immich/sdk --filter @immich/plugin-sdk --filter immich build
sudo -u immich env HOME=/opt/immich PATH=/opt/node-v24.15.0-linux-x64/bin:/usr/bin:/bin \
pnpm --dir /opt/immich/source-3.0.3 --filter immich --prod deploy /opt/immich/releases/3.0.3/server
sudo -u immich env HOME=/opt/immich PATH=/opt/node-v24.15.0-linux-x64/bin:/usr/bin:/bin \
pnpm --dir /opt/immich/source-3.0.3 --filter @immich/sdk --filter immich-web build
sudo cp -a /opt/immich/source-3.0.3/web/build /opt/immich/build/www
4. Configure the service and proxy
Create /etc/immich/immich.env with port 2283, PostgreSQL, Redis, media, and build paths. Set machine learning false, mode 0640, then create immich-server.service and proxy Nginx to localhost.
sudo systemctl daemon-reload
sudo systemctl enable --now immich-server
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d app.example.com -m admin@example.com --agree-tos --redirect
curl -f http://127.0.0.1:2283/api/server/ping
5. Create the first owner
Open https://app.example.com and create the first owner account. Disable open registration afterward if that matches your access policy.
Important files and data
- Application releases:
/opt/immich/releases - Build data:
/opt/immich/build - Media library:
/var/lib/immich - Protected environment:
/etc/immich/immich.env - Service:
/etc/systemd/system/immich-server.service
Health checks and logs
Run these checks after installation and after each upgrade:
curl -f http://127.0.0.1:2283/api/server/ping
sudo systemctl status immich-server postgresql redis-server nginx --no-pager
sudo journalctl -u immich-server -n 100 --no-pager
Routine maintenance
Review release notes and take a backup or snapshot before upgrading. Use the following playbook-aligned commands as the starting point:
sudo systemctl stop immich-server
# Back up PostgreSQL and /var/lib/immich, deploy a tested release, then migrate.
sudo systemctl start immich-server
curl -f http://127.0.0.1:2283/api/server/ping
Backup scope
- PostgreSQL database, including extension state
- All of
/var/lib/immich /etc/immich/immich.envand the active release/provenance record
A usable backup needs both application files and application data. Test restoration on a separate server; an untested backup is not a recovery plan.
Troubleshooting
- Confirm DNS with
dig +short app.example.combefore retrying Certbot. - Test the web-server configuration before reloading it:
sudo nginx -torsudo apache2ctl configtest. - Check free space with
df -hand listening ports withsudo ss -ltnup. - If a service fails, inspect its systemd journal before changing configuration.
- If the API will not start, check PostgreSQL extension availability and the protected environment file.
- A reverse-proxy upload failure may be caused by request buffering or body-size limits; the playbook disables buffering and allows unlimited request body size.
Security notes
- Do not paste passwords, API keys, repository credentials, private keys, or access tokens into tickets or public logs.
- Expose only the documented public ports. Keep database and application backend ports bound to localhost or a private network.
- Keep SSH access working before enabling UFW, then allow only the ports this guide lists.
- Renewal can be tested safely with
sudo certbot renew --dry-runwhere Certbot manages TLS.

