Runs Immich (self-hosted Google Photos alternative) on your server with your Internxt cloud storage mounted as an external library. Your photos live encrypted in Internxt's cloud, but you browse and search them through Immich's web UI.
Uses a custom rclone fork with automatic TOTP 2FA support for Internxt.
Your browser ──> Immich (Docker) ──> Host FUSE mount ──> Internxt Cloud
(photos) (Docker/Coolify) (rclone on host) (encrypted)
rclone runs on the host as a systemd service. Docker containers access the files through a bind mount. No privileged containers, no mount propagation hacks.
┌─────────────────────────────────────────────────────┐
│ Host (Linux) │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ rclone systemd service (immich-rclone) │ │
│ │ FUSE mount -> /mnt/immich-external-library │ │
│ │ Config: /etc/immich-rclone/rclone.conf │ │
│ │ Cache: /var/cache/immich-rclone/ │ │
│ └──────────────────────┬───────────────────────┘ │
│ │ bind mount (read-only) │
│ ┌──────────────────────▼───────────────────────┐ │
│ │ Docker (managed by Docker Compose / Coolify) │ │
│ │ │ │
│ │ ┌──────────────┐ ┌─────────────────────┐ │ │
│ │ │ immich-server│ │ immich-microservices│ │ │
│ │ │ (API + UI) │ │ (jobs + migrations) │ │ │
│ │ └──────────────┘ └─────────────────────┘ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ machine-learn│ │ ml-balancer │ │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ │ ┌─────┐ ┌───────────┐ │ │
│ │ │ pg │ │ redis │ │ │
│ │ └─────┘ └───────────┘ │ │
│ └────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ E2E-encrypted API (auto-2FA via TOTP)
▼
Internxt Cloud Storage
| Option | Guide | Best For |
|---|---|---|
| Docker Compose | DOCKER-SETUP.md |
Any Linux server with Docker. Includes Caddy, Cloudflare Tunnel, or Tailscale proxy options. |
| Coolify | COOLIFY-SETUP.md |
Servers already running Coolify. Deploys as a managed stack with Traefik. |
Both options share the same rclone host setup (Step 1 below) and the same Immich configuration. The only difference is how Docker is managed.
- A Linux server with Docker installed
- At least 50 GB disk (32 GB for rclone cache, rest for Immich)
- SSH access to the server (one-time, to run the install script)
- An Internxt account (with or without 2FA)
This step is the same for both deployment options.
SSH into your server and clone the repo (or just download install.sh):
git clone -b host-rclone https://github.com/thies2005/immich-rclone-coolify.git
cd immich-rclone-coolifyRun the install script:
sudo bash install.shThe script will walk you through everything:
-
Installs dependencies —
git,golang,fuse3(via apt, dnf, or yum) -
Checks FUSE — verifies
/dev/fuseexists, triesmodprobe fuseif not -
Compiles rclone — clones the custom fork and builds it (3-8 minutes)
-
Asks for your Internxt credentials:
- Email — your Internxt login email
- Password — your Internxt password (typed twice for confirmation)
- TOTP secret — only if your account has 2FA enabled (see below)
- Remote name — just press Enter for the default (
MyInternxt)
-
Creates files on your host:
File Purpose /opt/immich-rclone/rcloneThe compiled rclone binary /opt/immich-rclone/rclone-fuse-mount.shMount script used by systemd /opt/immich-rclone/rclone-fuse-cleanup.shUnmount script for clean shutdown /etc/immich-rclone/rclone.confYour Internxt credentials (obscured password) /etc/immich-rclone/mount.envrclone settings (cache size, timeouts, etc.) /etc/systemd/system/immich-rclone.servicesystemd unit file /etc/logrotate.d/immich-rcloneLog rotation config -
Starts the mount and waits up to 60 seconds for it to become ready
Getting your TOTP secret: When you originally set up 2FA on your Internxt account, you scanned a QR code. That QR code contains a
secret=parameter in base32 (e.g.JBSWY3DPEHPK3PXP). That is your TOTP secret. It is NOT a one-time code from your authenticator app. If you lost it, disable and re-enable 2FA on your Internxt account to get a new one.
ls /mnt/immich-external-libraryYou should see your Internxt files and folders listed. If you see files, the mount is working. If the directory is empty, check the logs:
journalctl -u immich-rclone -f
tail -f /var/log/immich-rclone/rclone.logFollow the guide for your chosen deployment method:
See DOCKER-SETUP.md for step-by-step instructions.
cp .env.example .env
# Edit .env — set DB_PASSWORD at minimum
docker compose -f docker-compose.standalone.yml up -dIncludes built-in options for Caddy (auto-HTTPS), Cloudflare Tunnel, or Tailscale Serve.
See COOLIFY-SETUP.md for step-by-step instructions.
Add the repo as a Docker Compose stack from GitHub, set DB_PASSWORD in Coolify, configure ML backend env vars, and deploy.
Open your Immich URL in a browser and create the admin account.
In Immich, go to Administration -> Settings -> Machine Learning and set the URL to:
http://immich-ml-balancer:80
This keeps backend hostnames private and lets the balancer handle local + remote ML failover.
- Log in to Immich
- Go to Administration (left sidebar) -> External Libraries
- Click Create Library
- Set the Import Path to exactly:
/mnt/external-library - Click Save
- Click the Scan button on the new library
The first scan downloads every file from Internxt and decrypts it through E2E encryption. This is slow:
| Library size | Expected time |
|---|---|
| 1,000 photos | ~15-30 minutes |
| 10,000 photos | ~2-4 hours |
| 50,000 photos | ~8-16 hours |
You can watch progress in Immich under Administration -> Jobs. Subsequent scans are fast -- only new or changed files are re-downloaded.
The install script creates a systemd service called immich-rclone that:
- Auto-starts on boot before Docker (
After=network-online.target) - Mounts your Internxt storage to
/mnt/immich-external-library - Auto-restarts on failure with 15-second backoff
- Cleans up stale mounts before each start
- Logs to both systemd journal and
/var/log/immich-rclone/rclone.log
/opt/immich-rclone/
├── rclone # compiled binary
├── rclone-fuse-mount.sh # mount script (systemd ExecStart)
└── rclone-fuse-cleanup.sh # unmount script (systemd ExecStop)
/etc/immich-rclone/
├── rclone.conf # Internxt credentials
└── mount.env # cache size, timeouts, etc.
/var/cache/immich-rclone/ # VFS cache (max 32 GB)
/var/log/immich-rclone/ # log file (auto-rotated weekly)
/mnt/immich-external-library/ # FUSE mount point (0 local disk)
| Component | Path | Allocation |
|---|---|---|
| rclone VFS cache | /var/cache/immich-rclone/ |
32 GB (hard cap) |
| Immich uploads | upload_data |
~4 GB |
| ML model cache | ml_cache |
~3 GB |
| PostgreSQL | postgres_data |
~2 GB |
| Redis | redis_data |
<100 MB |
| Docker + OS | (Docker root) | ~5 GB |
| External library | (FUSE mount) | 0 GB -- Internxt |
| Total | ~46 GB |
A 50 GB disk leaves very little headroom. If disk is tight, edit
RCLONE_VFS_CACHE_MAX_SIZEin/etc/immich-rclone/mount.envto a smaller value (e.g.16G) and restart the service.
sudo systemctl status immich-rclone # service status
ls /mnt/immich-external-library # verify mount has files
du -sh /var/cache/immich-rclone # check cache sizejournalctl -u immich-rclone -f # live systemd logs
tail -f /var/log/immich-rclone/rclone.log # rclone's own logsudo systemctl restart immich-rclonesudo nano /etc/immich-rclone/rclone.conf
sudo systemctl restart immich-rcloneOr re-run sudo bash install.sh -- it will ask for new credentials.
sudo nano /etc/immich-rclone/mount.env
sudo systemctl restart immich-rcloneSee ENV-VARIABLES.md for all available settings.
Re-running the install script rebuilds rclone from the latest source and restarts the service. Existing credentials are preserved:
sudo bash install.shsudo systemctl stop immich-rclone
sudo systemctl disable immich-rclone
sudo rm /etc/systemd/system/immich-rclone.service
sudo rm -rf /opt/immich-rclone /etc/immich-rclone /var/cache/immich-rclone /var/log/immich-rclone
sudo systemctl daemon-reloadCheck the host first:
ls /mnt/immich-external-libraryIf empty or missing, the host service isn't ready:
sudo systemctl status immich-rclone
journalctl -u immich-rclone -fIf the host mount has files but containers don't see them, restart the Coolify deployment.
- Verify credentials:
sudo cat /etc/immich-rclone/rclone.conf - Check for auth errors:
journalctl -u immich-rclone -f - 2FA login can take 30-60 seconds on first start
du -sh /var/cache/immich-rcloneThe cache is hard-capped at RCLONE_VFS_CACHE_MAX_SIZE (default 32G). To reduce:
sudo nano /etc/immich-rclone/mount.env
# Change RCLONE_VFS_CACHE_MAX_SIZE=16G
sudo systemctl restart immich-rcloneThis is expected. Internxt uses end-to-end encryption -- every file must be fully downloaded and decrypted before Immich can read it. Subsequent scans only process new or changed files and are fast.
| File | Description |
|---|---|
install.sh |
Run this first -- builds rclone, creates config, sets up systemd |
docker-compose.yml |
Coolify deployment (Immich + Postgres + Redis) |
immich-ml-balancer/nginx.conf.template |
Internal nginx template used by the ML balancer |
immich-ml-balancer/render-nginx.sh |
Startup renderer that builds nginx config from env vars |
docker-compose.standalone.yml |
Pure Docker deployment with Caddy/Cloudflare/Tailscale options |
Caddyfile |
Caddy reverse proxy config (for standalone deployment) |
.env.example |
Environment variable template (for standalone deployment) |
DOCKER-SETUP.md |
Pure Docker deployment guide |
COOLIFY-SETUP.md |
Coolify-specific setup details |
ENV-VARIABLES.md |
All environment variables |
- Immich -- self-hosted Google Photos alternative
- Internxt -- zero-knowledge encrypted cloud storage
- rclone -- cloud storage Swiss army knife (custom fork with TOTP 2FA)
- Docker Compose -- container orchestration
- Coolify -- open-source PaaS (optional deployment method)
MIT