Install Lumio on Netcup or Contabo.
Budget VPS with EU data centers — the cheaper siblings of Hetzner. The process is the same; here are the provider-specific differences and a compact deploy path.
Why Netcup / Contabo?
- Cheap and EU-based — GDPR-friendly locations in Germany/Austria
- Static public IP — no CGNAT fiddling, Caddy obtains HTTPS automatically
- Difference from Hetzner: no separate cloud firewall — securing happens via ufw in the system
- Contabo is the cheapest (lots of RAM/storage) but shares the CPU more; Netcup sits in between
Step 1 — Order a server
- Image: Ubuntu 22.04 LTS
- Location: pick an EU/DE data center
- Size: at least 4 GB RAM (photos only), 8 GB with video; watch for real vCPUs
- Add an SSH key (or set it up after the first login)
Step 2 — Secure it & Docker
Without a cloud firewall, ufw is mandatory here. Condensed — the full version (non-root user, SSH hardening, fail2ban) is in the Hetzner guide:
sudo apt update && sudo apt upgrade -y
# Firewall — only what's needed
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw --force enable
# Docker engine + Compose plugin
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# log back in, then test:
docker run --rm hello-world Step 3 — DNS & deploy Lumio
Point an A record of your domain at the server IP, then:
sudo mkdir -p /opt/lumio && sudo chown $USER:$USER /opt/lumio
cd /opt/lumio
git clone https://github.com/markusthiel/lumio.git .
cp .env.example .env
# Generate secrets
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')|" .env
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -base64 32 | tr -d '/+=')|" .env
sed -i "s|^SESSION_SECRET=.*|SESSION_SECRET=$(openssl rand -base64 32 | tr -d '/+=')|" .env
sed -i "s|^S3_ACCESS_KEY=.*|S3_ACCESS_KEY=$(openssl rand -hex 12)|" .env
sed -i "s|^S3_SECRET_KEY=.*|S3_SECRET_KEY=$(openssl rand -base64 32 | tr -d '/+=')|" .env
# Set the domain (Caddy obtains Let's Encrypt automatically):
# LUMIO_HOST=photos.yourstudio.com
# PUBLIC_URL=https://photos.yourstudio.com
# S3_PUBLIC_URL=https://photos.yourstudio.com/s3
nano .env
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d Step 4 — Create an admin & log in
docker compose exec api npm run create-admin \
-- --email=you@yourstudio.com --password=atleast12chars
Log in at https://photos.yourstudio.com. Caddy fetches the certificate on the first request — that takes a few seconds. Backups are covered by the
backup guide.
Common questions about Netcup & Contabo
Netcup, Contabo or Hetzner — which to pick? +
All three have data centers in Germany/EU and are GDPR-friendly. Hetzner is the reference provider with very good price/performance and dedicated-CPU options. Netcup is similarly solid, often with a bit more RAM for the money. Contabo is the cheapest and gives you lots of RAM and storage, but shares the CPU more heavily with others (oversubscribed) — usually fine for a photo studio, borderline for video-heavy workflows.
Is there a cloud firewall like Hetzner's? +
Not in the same form. Hetzner Cloud has a cloud firewall in the console on top of the OS firewall. With Netcup and Contabo you generally rely on the firewall in the operating system (ufw). That's why securing with ufw matters especially here — only 22, 80 and 443 open.
Is the performance enough for Lumio? +
For a solo studio, yes. Watch for enough RAM (4 GB photos only, 8 GB with video) and that they are real vCPUs. On Contabo's cheap plans the CPU is shared — transcoding then takes longer. If you have a lot of video, take a plan with dedicated cores or go with Netcup/Hetzner.
Where are the servers, in terms of GDPR? +
Netcup runs data centers in Germany and Austria, Contabo has locations including Germany (selectable at order time), Hetzner in Germany and Finland. For GDPR-sensitive client data you simply pick an EU location — that's one of the main reasons to self-host in the first place.
Do I need a static IP? +
VPS from these providers come with a static public IPv4 — unlike a home connection you don't have to worry about CGNAT or DynDNS. You just point an A record of your domain at the server IP, and Caddy obtains the HTTPS certificate automatically.
Ready for your own gallery?
Source code on GitHub, questions and discussions there too. If anything in the guide trips you up, reach out — we're happy to improve the docs.