- Showcase video: https://www.youtube.com/watch?v=FrCaie-2YKk
Introductions
I wanted to set up a simple self-hosted photo backup server with Immich on RHEL.
Most Immich guides are written for setups that do not have to deal with RHEL-specific SELinux behavior. The installation itself is not too bad, but getting the permissions right can be frustrating if you have never done it before.
This post walks through how to run Immich on RHEL with rootless Podman and Tailscale, with the extra steps needed to make it work cleanly.
1. Download the Immich Files (Default Setup)
First, create the working directory and pull down the official Immich deployment files.
| |
2. Install podman-compose
Now we need a way to run this compose file. RHEL keeps its official repositories incredbly strict for enterprise stability. To get community-standard tools like podman-compose, we have to switch to root, enable CodeReady Builder (CRB), and get into Fedora’s Extra Packages for Enterprise Linux (EPEL).
| |
Tip: If the CRB repository does not work, you can always bypass it by installing pip and installing podman-compose through Python instead.
| |
3. Edit SELinux Contexts
Next, edit the docker-compose.yml file. Because RHEL uses SELinux, it blocks containers from touching host files. We have to explicitly add permissions to the volume mounts inside the file.
| |
| |
When you are defining your volume paths in the compose file, append the correct SELinux labels:
- Add a lowercase
:zto your photo uploads and database volume folder so multiple Immich containers can share that directory without locking each other out.
4. Fire It Up
With the files configured, start the stack in detached mode.
| |
5. Fix PostgreSQL Permissions for Rootless Podman
If the database container fails with permission errors under rootless Podman, fix the ownership on the host and restart the stack. Because we are running this securely as a normal user instead of root, the host machine doesn’t recognize the container’s internal PostgreSQL user. We have to translate those permissions.
| |
The podman unshare command drops us into the container’s user namespace. It maps the container’s internal database user to a large, unprivileged user ID on the host machine, fixing the permission-denied errors without compromising security.
6. Secure Remote Access with Tailscale
The server is running, but how do you access it securely without exposing ports to the internet? Tailscale makes this effortless.
Install Tailscale using their official script:
| |
Once installed, bring the node online:
| |
Copy the authentication link provided in the terminal, paste it into your browser, and authenticate. That’s it. Anything connected to your Tailscale mesh network can now access your new Immich instance securely.
Convert Containers Into a Service with Quadlet
If you want to convert your containers into a proper user service, follow these steps. With the following steps, you can have immich auto start if the system restarts and so on.
7. Transition to Quadlet (Kubernetes Style)
We can use Quadlet to treat the containers as a native systemd service. First, generate a Kubernetes YAML blueprint from the stack.
| |
8. Networking in a Pod
Inside a Pod, containers share the same network stack. That means Immich needs to resolve database and redis to 127.0.0.1. Add this to immich.yaml.
| |
9. Configure Quadlet
Move your manifest to the systemd generator directory and create the .kube file.
| |
immich.kube content:
| |
10. Enable and Boot
Enable lingering so the service keeps running even when you are not logged in, then start it.
| |
11. Verification
Check logs with:
| |
If you see database system is ready, the service is up.
12. Safe Upgrade (If You Followed This Guide)
This flow is designed to avoid breaking your rootless Podman + Quadlet setup and keep your database safe.
- Check the Immich release notes for breaking changes.
- Stop the running service.
- Pull the latest images.
- Regenerate the Pod spec if the compose file changed.
- Re-apply permissions if the database fails to start.
1) Read the release notes
Go to the Immich GitHub releases page and scan for any migration notes or changes to environment variables.
2) Stop the running service
| |
3) Pull the latest images
| |
4) Regenerate the Pod (if the compose file changed)
If you updated docker-compose.yml or .env, regenerate the manifest and re-apply the Quadlet file.
| |
5) Start the service
| |
6) Fix database permissions if needed
If the database fails to start due to permission errors, re-apply the rootless ownership mapping and restart.
| |
7) Verify
| |