Nextcloud v34 vs Immich: The Ultimate Self-Hosted Photo Backup Guide
Compare Nextcloud v34 and Immich for photo backup in your homelab. Step-by-step Docker Compose install guides, performance expectations, and troubleshooting.
Introduction
Choosing the right platform for self-hosted photo backup is a critical decision for any homelab enthusiast. Nextcloud has long been the Swiss Army knife of file synchronization, offering a complete suite of productivity tools alongside file storage. In 2026, Nextcloud v34 (specifically v34.0.3) continues this legacy with improved performance and a refined interface. On the other hand, Immich has emerged as a dedicated solution, engineered specifically for photo and video management, boasting machine-learning-powered search and a mobile-first experience that rivals commercial cloud services.
This guide aims to provide a technical, side-by-side comparison and installation walkthrough for both systems. You will learn how to deploy Nextcloud v34.0.3 and Immich using Docker Compose, configure them for a homelab environment, and understand the critical differences in storage architecture, backup strategies, and hardware expectations. We will not provide fictional benchmark numbers; instead, we will focus on the architectural factors that influence performance.
By the end of this guide, you will have a clear understanding of which platform fits your specific needs—whether you require a full-fledged file sync suite or a laser-focused photo management tool. Both installation paths are presented with production-ready Docker Compose files, environment variable management, and common troubleshooting steps. The goal is to give you a functional deployment that you can extend and harden according to your homelab standards.
Let's dive straight into the prerequisites, followed by a step-by-step installation for each platform. We will then cover advanced configurations like reverse proxies and backups, and conclude with a detailed FAQ section.
Prerequisites
Before you begin, ensure your homelab server meets the following baseline requirements. These are typical estimates; actual usage will vary based on the number of users, library size, and enabled features like full-text search or facial recognition.
| Component | Nextcloud v34 (Recommended) | Immich (Recommended) | Notes |
|---|---|---|---|
| CPU | 2-4 cores (x86_64/ARM64) | 4-6 cores (x86_64/ARM64) | Immich's ML pipeline benefits from more cores. |
| RAM | 2-4 GB (typical) | 4-6 GB (typical) | Allocated to DB, PHP-FPM, and Redis. |
| Storage | 20 GB + data volume | 50 GB + data volume | Use SSD for DB volume, HDD for bulk data. |
| OS | Ubuntu 22.04/24.04, Debian 12 | Ubuntu 22.04/24.04, Debian 12 | Linux with kernel >= 5.10 for io_uring support in DB. |
| Software | Docker Engine 24+, Docker Compose v2 | Docker Engine 24+, Docker Compose v2 | Ensure docker compose plugin is installed. |
Core Services Required by Both:
- Reverse Proxy (Optional but Recommended): Nginx Proxy Manager, Traefik, or Caddy. Needed for SSL termination and domain-based routing.
- Domain Name: A subdomain like
cloud.example.comorphotos.example.com. If you don't have a domain, configure access via IP and port, but SSL will be tricky. - Port Availability: Ensure ports
80,443, and8080(for Immich) are free or properly mapped.
Step-by-Step Installation Guide
We will deploy both applications in separate directories with dedicated .env files. This ensures isolation and simplifies upgrades. We are using the latest verified versions: Nextcloud v34.0.3 and Immich latest (check the official releases page before pinning).
Part 1: Nextcloud v34.0.3 Setup
Step 1: Create Directory Structure and .env File
First, create the base directory and navigate into it. Then, create the .env file that will hold your secrets. Never commit this file to your Git repository.
mkdir -p ~/nextcloud-34 && cd ~/nextcloud-34 &&
touch .env && chmod 600 .env
Now, edit the .env file with your preferred text editor (e.g., nano .env). Populate it with the following content. Replace the passwords with strong, unique values.
# Nextcloud v34.0.3 Installation Environment Variables
NEXTCLOUD_VERSION=34.0.3
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD=choose_a_strong_password
MYSQL_ROOT_PASSWORD=choose_a_different_strong_root_password
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=choose_a_strong_admin_password
Step 2: Create Docker Compose File
Create a docker-compose.yml file in the same directory. This file defines the Nextcloud application, a MySQL database, and a Redis cache. The configuration is complete and production-ready.
services:
db:
image: mariadb:11.4
restart: always
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
volumes:
- ./db:/var/lib/mysql
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7.2-alpine
restart: always
command: redis-server --appendonly yes
volumes:
- ./redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
app:
image: nextcloud:${NEXTCLOUD_VERSION}
restart: always
ports:
- "8080:80"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./nextcloud:/var/www/html
- ./data:/var/www/html/data
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=redis
- NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
- NEXTCLOUD_ADMIN_PASSWORD=${NEXTCLOUD_ADMIN_PASSWORD}
- NEXTCLOUD_TRUSTED_DOMAINS=localhost,127.0.0.1,cloud.example.com
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/status.php"]
interval: 30s
timeout: 10s
retries: 5
volumes: {}
Step 3: Deploy Nextcloud
Run the following command to pull the images and start the containers in detached mode.
cd ~/nextcloud-34 && docker compose up -d
Wait for the health checks to pass. You can monitor the status with docker compose ps. Once the app service is healthy, navigate to http://your-server-ip:8080. You should see the Nextcloud login page. Log in with the admin credentials you set in the .env file.
Part 2: Immich Setup
Immich consists of multiple services: a server, a machine-learning worker, a Redis cache, a Postgres database, and a web interface. We will use the official docker-compose.yml from the Immich GitHub repository, but we will parameterize the versions.
Step 4: Create Directory Structure and .env File
mkdir -p ~/immich && cd ~/immich &&
touch .env && chmod 600 .env
Populate the .env file with the following. Important: Immich requires a specific version tag for the server and machine-learning images. As of this writing, the latest release is v1.118.0. Since this is a rapidly moving target, we will use release as a tag, but you must check the official GitHub releases page before pinning a version. The version above may be outdated by now.
# Immich Installation Environment Variables
IMMICH_VERSION=release
DB_PASSWORD=choose_a_strong_db_password
DB_USERNAME=immich
DB_DATABASE_NAME=immich
Step 5: Create Docker Compose File
Create a docker-compose.yml file. This is a trimmed-down but fully functional version of the official Immich compose file. It includes the database, server, machine learning, and web frontend.
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION}
command: ['start.sh', 'immich']
volumes:
- ./library:/usr/src/app/upload
- ./model-cache:/usr/src/app/.cache
env_file:
- .env
environment:
- DB_HOSTNAME=immich-postgres
- DB_PORT=5432
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- DB_DATABASE_NAME=${DB_DATABASE_NAME}
- REDIS_HOSTNAME=immich-redis
ports:
- 2283:3001
depends_on:
- immich-redis
- immich-postgres
restart: always
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION}
volumes:
- ./model-cache:/cache
env_file:
- .env
environment:
- DB_HOSTNAME=immich-postgres
- DB_PORT=5432
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
- DB_DATABASE_NAME=${DB_DATABASE_NAME}
- REDIS_HOSTNAME=immich-redis
depends_on:
- immich-redis
- immich-postgres
restart: always
immich-postgres:
container_name: immich_postgres
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_DB=${DB_DATABASE_NAME}
volumes:
- ./pgdata:/var/lib/postgresql/data
restart: always
immich-redis:
container_name: immich_redis
image: docker.io/redis:6.2-alpine
restart: always
Step 6: Deploy Immich
cd ~/immich && docker compose up -d
After the containers start, give the server a minute to initialize. Access the web UI at http://your-server-ip:2283. Create your admin account on the first visit.
Advanced Setup and Optimization
Reverse Proxy and SSL
For a professional setup, you should place a reverse proxy in front of both services. This allows you to use standard ports (443) and enable HTTPS.
Step 7: Configure Reverse Proxy (Example with Nginx Proxy Manager)
Assuming you have Nginx Proxy Manager (NPM) running, add a Proxy Host for cloud.example.com pointing to http://your-server-ip:8080 (Nextcloud) and another for photos.example.com pointing to http://your-server-ip:2283 (Immich). Enable SSL via Let's Encrypt.
For Nextcloud, you must update the NEXTCLOUD_TRUSTED_DOMAINS in your docker-compose.yml and restart the container.
cd ~/nextcloud-34 && docker compose up -d
Backups
Step 8: Backup Strategy
- Nextcloud: Stop the containers, back up the
nextcloud(config) anddatadirectories, and dump the MySQL database.cd ~/nextcloud-34 && docker compose exec -T db mysqldump -u root -p"${MYSQL_ROOT_PASSWORD}" --all-databases > backup.sql && tar -czf nextcloud_backup.tar.gz ./nextcloud ./data backup.sql - Immich: Immich provides an official backup script. It is best to use
docker compose execto dump the Postgres database and copy thelibraryfolder.cd ~/immich && docker compose exec -T immich-postgres pg_dump -U ${DB_USERNAME} -d ${DB_DATABASE_NAME} > immich_db_backup.sql && tar -czf immich_backup.tar.gz ./library immich_db_backup.sql
Optional Hardening
Warning: The following settings are advanced and can break containers if applied incorrectly. They must be adapted for each specific application and image. Do not copy them blindly.
For Nextcloud, you might add a security_opt and read_only to the app service, but this requires careful volume management for the data and config directories. For Immich, the machine-learning container requires a writable /cache directory. Adding cap_drop might break network operations. Always test in a staging environment first.
Troubleshooting Common Errors
| Common Error | Cause | Solution |
|---|---|---|
Nextcloud is not installed loop |
The NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD environment variables are not being read correctly. |
Ensure the .env file is in the same directory as your docker-compose.yml and that the variables are correctly named. Run docker compose config to see the resolved environment variables. |
File not found in Nextcloud when accessing data |
The ./data volume is not mounted correctly or has permission issues. |
Check the volume path in your compose file. On the host, run id -u && id -g and verify against the image's documentation. The default user in the Nextcloud image is www-data (UID 33). You may need to adjust host directory ownership. |
Immich server fails to start with ECONNREFUSED for Postgres |
The Postgres container is not healthy when the server tries to connect. | Add a depends_on condition for the server service to wait for the database healthcheck. Increase the healthcheck interval in the Postgres service definition. |
| Immich ML container crashes with OOMKilled | The machine-learning model requires more memory than the container has. | Increase the memory limit for the container in the compose file (e.g., mem_limit: 4g). Also, check the IMMICH_MACHINE_LEARNING_WORKERS environment variable; reduce the number of workers to lower memory usage. |
| Slow uploads to Nextcloud | The PHP memory limit is too low, or the opcache is not configured. |
Edit the nextcloud container's php.ini via a custom config file mounted into the container. Increase memory_limit to 1024M and upload_max_filesize to 10G. |
| Immich shows a blank screen after login | The web frontend cannot connect to the server API. | Check the browser's developer console for CORS errors. Ensure the IMMICH_SERVER_URL and IMMICH_WEB_URL environment variables are set correctly if you are using a reverse proxy. |
docker compose up fails with a port conflict |
Another service is already using port 8080 or 2283. | Change the host port mapping in your compose file (e.g., 8081:80 for Nextcloud). |
Conclusion and FAQ
Choosing between Nextcloud and Immich is not a matter of which is objectively better, but which is better for your specific workflow. Nextcloud v34 offers an all-in-one solution that provides file sync, collaborative editing, and a robust API, making it ideal for users who want to replace Google Drive entirely. Immich, with its dedicated focus on media, delivers a superior photo management experience with features like semantic search and timeline clustering that are typically found in commercial services like Google Photos.
For a homelab, you can run both side-by-side without issue, as we have demonstrated. This gives you the flexibility of a general-purpose file sync tool and the specialized power of a media manager. Remember to always check the official release notes for updates, as the self-hosted ecosystem evolves rapidly.
FAQ
1. Can I migrate from Nextcloud's built-in photos app to Immich?
Yes, but there is no direct one-click migration tool. You can use the Nextcloud API to download all photos and then use Immich's web uploader to re-upload them. For a large library, consider using a CLI tool like rclone to sync from the Nextcloud WebDAV endpoint to a local folder, and then use the Immich CLI to import that folder.
2. Which platform uses less RAM on a typical homelab server?
Nextcloud is generally lighter on RAM if you disable expensive features like full-text search or server-side encryption. A typical Nextcloud deployment with a few users might use 1-2 GB of RAM. Immich, due to its machine-learning components, typically requires 3-4 GB of RAM to function smoothly. However, these are estimates; the actual usage depends on the number of background jobs and active users.
3. Is it safe to expose these services directly to the internet?
No, it is not recommended. You should always place a reverse proxy with HTTPS and strong authentication in front of them. For Nextcloud, use the built-in brute-force protection and consider adding two-factor authentication. For Immich, ensure your instance is not publicly accessible without a VPN or a secure proxy, as it is a newer project and may not have as many hardening features as Nextcloud.
4. How do I update Immich to the latest version?
Immich releases new versions frequently. The easiest method is to pull the latest images and recreate the containers. First, check the official release notes for any breaking changes. Then, run cd ~/immich && docker compose pull && docker compose up -d. It is good practice to back up your database and library directory before performing an update.
5. Can I use an external database for Nextcloud instead of the MariaDB container?
Yes, you can. You can configure Nextcloud to use an external PostgreSQL or MySQL instance. This is useful if you already have a centralized database server in your homelab. You would remove the db service from the compose file and change the MYSQL_HOST environment variable in the app service to point to your external database host. You will also need to manually create the database and user on the external server.