Self-Host Immich: Open Source Google Photos Alternative

Immich is a free and open source alternative to Google Photos, with a focus on privacy. Both the server software and the mobile client application, are developed in the open on GitHub. Thanks to the container technology, deploying a private, self-hosted instance of Immich is quite easy. In this tutorial, we learn how to run a self-hosted Immich instance using Docker, to manage and backup our photos and videos.

In this tutorial you will learn:

  • How to use Docker or Podman to deploy a self-hosted instance of Immich
  • How to access Immich from browser and from the mobile app
Introduction to Immich
Introduction to Immich
Category Requirements, Conventions or Software Version Used
System Distribution-agnostic
Software Docker/Podman
Other None
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

Introduction

The cloud is just someone else’s computer, and you shouldn’t trust it. Android is the most widespread mobile operating system; by consequence, the default application used to manage and sync photos and videos on the OS made by Google, Google Photos, is used daily by million of users. Relying on proprietary software for such as an essential task as the backup of your beloved pictures and videos, is not a good idea, since you are not really in control of your data. Immich is a free and open source alternative to Google Photo, which we can easily deploy using Docker, on our own machines and our own storage. Let’s see how.

Using Docker/Podman to run Immich

The easiest and most straightforward way to run a self-hosted instance of Immich, is by using Docker (or Podman) and docker-compose. A pre-configured docker-compose.yml file is available on the GitHub repository of the project. We can download it straight from the command line, by using the following command:

$ curl -LO https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml



The command above downloads the file in our current working directory. Inside the file, some variables are used to provide confidential information, such as the Postgres database username and password, plus essential information such as the path where uploaded media should be saved. For obvious reasons, this information cannot be hard-coded inside the file; however, they are automatically read from an .env environment file, which must be located in the same directory as the compose file. A sample of the file, can be downloaded from GitHub:

$ curl -L -o .env https://github.com/immich-app/immich/releases/latest/download/example.env

Inside the file, we can see all variables have a default value:

# You can find documentation for all the supported env variables at https://im

# The location where your uploaded files are stored
UPLOAD_LOCATION=./library
# The location where your database files are stored
DB_DATA_LOCATION=./postgres

# The Immich version to use. You can pin this to a specific version like "v1.7
IMMICH_VERSION=release

# Connection secret for postgres. You should change it to a random password
DB_PASSWORD=postgres

# The values below this line do not need to be changed
##############################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

As clearly explained in the comments, the UPLOAD_LOCATION and DB_DATA_LOCATION variables are used to pass the path of the host directory which will be used to store uploaded images, and the one used for Postgres database files. The DB_DATABASE_NAME, DB_USERNAME and DB_PASSWORD variables, instead, are used to pass the database name, username, and password. (the database is automatically created the first time we launch the stack).

In recent version of Docker CE (Community Edition), docker-compose is installed as a plugin, so, you should substitute any docker-compose command in the examples with docker compose. If you are using the deprecated Python version of docker-compose, instead, you can just follow along. Remember that you can use docker-compose even if you are using Podman under the hood. All you need to know is basically star the Podman socket.

Using SELinux

To let bind-mounts described in the docker-compose.yml file work when SELinux is enabled, we need to add z as a mount option, so that the SELinux context of the host directories is automatically set to container_file_t. The lines we need to change are 17, 36 and 73:

volumes:
   - ${UPLOAD_LOCATION}:/usr/src/app/upload:z
volumes:
   - ${UPLOAD_LOCATION}:/usr/src/app/upload:z
volumes:
   - ${DB_DATA_LOCATION}:/var/lib/postgresql/data:z

Enabling memory overcommit

Before we launch the containers stack, it is recommended to enable memory overcommit, otherwise certain operations mail fail under low memory conditions. To permanently enable memory overcommit, we can edit the /etc/sysctl.conf file, or create a dedicated drop-in file under /etc/sysctl.d, with the following content:

vm.overcommit_memory = 1



The change will be automatically applied at boot; to make it, immediately effective, we can run:

$ sysctl -p

Launching the container stack

To launch the container stack, we run:

$ docker-compose up

Since none of the containers maps to a host privileged port, we can run docker-compose without using root privileges (it is still possible to let an unprivileged container use a privileged port). When running the command, you may see the following error:

ERROR: The Compose file './docker-compose.yml' is invalid because:
'name' does not match any of the regexes: '^x-'

This means you are using the legacy version of docker-compose. As a workaround, it is enough to comment line 9 of the docker-compose file:

# name: immich

Once done, just relaunch the docker-compose up command; if everything goes as expected, after few seconds, we should be able to access the Immich admin page athttp://localhost:2283:

Immich welcome page on http://localhost:2283
Immich welcome page on http://localhost:2283

To create the admin account, just click on the “Getting started” button, and fill the form with required information:

Creating the Immich admin account
Creating the Immich admin account

Using a secure connection

If you want to safely access your Immich instance from outside your home network, you basically have two options: the first one consists into connecting using a VPN such as Wireguard; the second involves the use of an SSL/TLS certificate. If you have a public domain, you can obtain a valid certificate from Let’s Encrypt; if you are setting up Immich for your personal use only, as an alternative, you can generate and use a self-signed certificate.



In this context, the easiest way to make use of the certificate, is to serve Immich via a reverse-proxy such as Nginx or Caddy. The reverse proxy can either run as a container, perhaps as part of the Immich stack, or run directly on the host. Below, you can see an example of an Nginx reverse-proxy configuration which passes all requests from https://immich.mydomain.com to http://192.168.0.39:2283 (local IP and port of the machine where containers are running), using a certificate obtained from Let’s Encrypt:

server {
  listen 443 ssl;
  server_name immich.mydomain.com;

  ssl_certificate     /etc/letsencrypt/live/immich.mydomain.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/immich.mydomain.com/privkey.pem;
  ssl_session_cache builtin:1000 shared:SSL:10m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
  ssl_prefer_server_ciphers on;

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

When using such configuration, we should also allow traffic through port 443. If using UFW as a firewall manager, we can run:

$ sudo ufw allow "WWW Secure"

When using Firewalld, instead, to permanently allow traffic through port 443 in the default zone, we can run:

$ sudo firewall-cmd --permanent --add-service=https
$ sudo firewall-cmd --reload

To apply the rule to a specific zone, instead, we can pass the name of the zone name as argument to the --zone option.

Installing the Android App

The Immich client app is available both on the Android Play Store, and on the iOS App Store. To access our Immich server, we launch the application and login with the account we created during installation. As endpoint URL, we use the server IP and the /api path:

The Android Immich app
The Android Immich app

Closing thoughts

Immich is a free and open source alternative to Google Photos to manage and backup videos and photos on mobile devices. In this tutorial, we saw how to deploy Immich using Docker. To securely access our self-hosted Immich instance from outside our local network, we can either connect using a VPN or use a TLS/SSL certificate and a reverse-proxy. As part of the tutorial, we saw a possible Nginx configuration to achieve such setup.