Self-hosting photos and documents

I really like Google Photos and our old videos and photos are there, but after they stopped unlimited storage, we put the videos (around 3TB) in OneDrive so we now have a mish-mash of Google Photos and OneDrive. We mainly use OneDrive for documents (plus some collaborative ones in Google Drive). The Microsoft OneDrive Family subscription is due for renewal in April and, although it is a good deal for 6TB, I want to stop sending money to Big Tech in US for various reasons… What to do?

Requirements

  1. I already have a mirror of OneDrive on our home server (which has a 6TB old-school hard disk), so I wanted to keep this arrangement where we have a local copy of everything.
  2. The family photos and videos are curated in that I have always organised them into folders “yyyy/yyyy-mm-dd – Short description” and I want to keep this structure.
  3. I want something where all 4 of us in the family can each save their own photos, but then share some of them with the family, so we need separate accounts, plus another common account for the family.
  4. We want the same for documents (separate accounts, but easy to share), ideally with the option of E2EE for personal files such as financial and health records.
  5. We want a separate account for our sons’ schools and activities as these need to be curated to find relevant photos – we really don’t want (literally) thousands of photos clogging up the main family account.

Research and Planning

After a lot of experiments with EU based services (such as Proton, pDrive, Internxt, Jottacloud – all of which are good in many ways), I couldn’t find one that really did everything I wanted, especially in relation to our photos and videos .

Then I came across Immich and was blown away. This set me on the path of looking for self-hosting and after a lot of trial and error, I have a configuration that I’m very happy with. If you’re not familiar with it, Immich is modelled on Google Photos, but actually has more features and the image analysis is all private. The face recognition works very well and is great to filter the “photo dump” we got from the school and various summer camps, so we can find photos that include our sons. The context and OCR is also useful and the flexibility of the searching, such as by file name or camera is very helpful.

So, how to make this work reliably and at a sensible cost? Again, more research and experiments with different VPS providers, storage costs, document storage options (tried Pydio, Seafile and others).

Result

  1. VPS runs Immich and Nextcloud applications. Currently using 4 vCPU + 8GB + 150 GB disk and it works just fine.
  2. 5TB StorageBox for all the files as this is very cost effective versus adding storage to the VPS. This is connected to the VPS over a secured connection, so it all stays private.
  3. Immich thumbnails and processed videos are kept on the VPS so browsing is very fast. The full images/videos are in StorageBox, but they are still very responsive.
  4. Nextcloud documents are the same – all on StorageBox but with code and data caching in the VPS, it works well.
  5. Security
    • no disk encryption, relying on HTTPS and trusting the hosting providers not to go snooping – the companies all appear to take security very seriously. I tried the Nextcloud server-side encryption, but given the keys are saved on the server, I’m not sure what the point is and it certainly slows it down.
    • For sensitive documents, I’m using Crytomator on a Nextcloud folder called “Vault”, so we know not to mess with it. I tried the Nextcloud E2EE, but found it flaky.
    • Both Immich and Nextcloud have Microsoft OAuth login (using Azure Entra), to give a smoother experience and 2FA.
    • I have configured Cloudflare to provide some protection against VPS abuse.
  6. The home server is Windows 11 Pro with WSL running a scheduled bi-directional rsync:
    • The curated Family media folders are exported to StorageBox every midnight. I periodically add new photos or correct dates etc, so this pushes the changes to Immich as external files, which is scheduled to scan for changes at 2AM. The ML processing for face recognition runs overnight so everything is ready the next day. The original scan took several days, but that was a once-off situation.
    • The uploaded photos from our mobiles, Immich database, Nextcloud documents/database/config files are all imported from StoraeBox at 2AM

I am an experienced software developer, but I’d have to say I didn’t find it easy to get this working the way I wanted, so I can understand why people use turnkey cloud services. There are a lot of rough edges in configuring self-hosting, so the rest of this goes into the details to hopefully make it easier for others.

Details, details…

VPS

Setup

  1. Change default SSH port (this is just to reduce the volume of bot attacks) 1
  2. Install Fail2ban (reduces risk of successful bot attack) 2
  3. Configure Firewall for new SSH and HTTPS only (reduces attack surface) 3
  4. Install Apache (for Nextcloud and Immich) 4
  5. Configure DNS for domain (required to allow HTTPS) 5
  6. Create certificate for HTTPS (using free Lets Encrypt) 6
  7. Configure Apache (for Immich reverse proxy) 7
  8. Install and configure AutoFS (secured SMB/CIFS connection to Storage) 8

Immich

  1. Install Docker Compose
  2. Install Immich via Docker

Nextcloud

  1. Install PHP
  2. Install Database (MariaDB or Postgres)
  3. Install Nextcloud via PHP

Cloudflare (recommended, or use Tailscale etc)

  1. Configure Cloudflare
  2. Update Firewall to restrict to Cloudflare (exception for Home IP to allow fallback access)

OAuth (optional)

  1. Configure Azure Entra (or Google etc)
  2. Configure Immich OAuth
  3. Configure Nextcloud OAuth

Home Server

  1. (Windows only) Install WSL and configure to autostart
  2. Create and deploy SSH key to access Storage
  3. Install WinSCP for checking Storage
  4. Install rsync
  5. Configure crontab for rsync export/import

Storage

  1. Nothing to do (SSH key is deployed from Home Server)

Notes

  1. sudo nano /lib/systemd/system/ssh.socket
    #edit [Socket] section with new SSH port
    ListenStream=0.0.0.0:NNNNN

    sudo systemctl daemon-reload
    sudo systemctl restart ssh.socket

    ↩︎
  2. sudo apt install fail2ban
    sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

    sudo nano /etc/fail2ban/jail.local
    #edit [sshd] section with new SSH port
    port = NNNNN

    sudo systemctl restart fail2ban
    ↩︎
  3. iptables -I INPUT -p tcp -m multiport --dports NNNNN -j ACCEPT #allow new SSH port
    iptables -I INPUT -p tcp -m multiport --dports https -j ACCEPT #allow https
    iptables -A INPUT -p tcp -m multiport -j DROP #block everything else

    ↩︎
  4. sudo apt install apache2
    sudo a2enmod ssl
    ↩︎
  5. Go to your DNS service provider and add A record for immich.MYDOMAIN.COM pointing to the VPS IP address
    ↩︎
  6. sudo apt install -y certbot python3-certbot-apache
    sudo certbot --apache -d immich.MYDOMAIN.COM

    ↩︎
  7. sudo a2enmod proxy_http

    sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf
    #Edit within immich.MYDOMAIN.COM virtual host block: 2283 is default immich port
    ProxyPass / http://127.0.0.1:2283/ timeout=600 upgrade=websocket
    ProxyPassReverse / http://127.0.0.1:2283/

    ↩︎
  8. sudo apt install autofs smbclient cifs-utils

    sudo nano smb-credentials
    #edit file with StorageBox credentials
    username=uNNNNNN
    password=PASSWORD


    chmod 600 smb-credentials


    sudo nano /etc/auto.master
    #edit file
    /mnt /etc/auto.smb --timeout=60 --ghost

    sudo nano /etc/auto.smb

    #edit file, delete existing content. docs needs to have "www-data" user id (33 in my case)
    storage-box -fstype=cifs,rw,iocharset=utf8,seal,credentials=/home/USER/smb-credentials,file_mode=0660,dir_mode=0770,_netdev,cache=none ://uNNNNNN.your-storagebox.de/backup
    docs -fstype=cifs,iocharset=utf8,rw,seal,credentials=/home/USER/smb-credentials,file_mode=0660,dir_mode=0770,_netdev,cache=none,uid=33,gid=33 ://uNNNNNN.your-storagebox.de/backup/docs


    sudo chmod -x /etc/auto.smb #default is executable, so remove
    apt install linux-modules-extra-$(uname -r) #fix utf8 in filenames
    sudo systemctl stop autofs

    #test to check mount works with authentication
    sudo automount -f -v


    #open another terminal
    ls /mnt/storage-box
    ls /mnt/docs

    #start for real
    sudo systemctl restart autofs
    ↩︎