Skip to content

Running the service is the easy part. Operating it is the challenge.

Ready-made Docker Compose setups for 120+ apps, all behind the same protection — HTTPS and access control, isolated networks, secrets in files. Set up once, reused by every service you self-host.

Starting a container is one command. Keeping the service reachable only to the people who should reach it, patched, and recoverable when the disk goes — that is what these guides are about.

Each of these runs on your own machine with Docker and nothing else — no proxy, domain or certificate, and none of the protection a server gets. The secrets ship empty; each block fills the ones its stack requires. Clone once, then run a block from the repository root:

Terminal window
git clone https://github.com/rubennati/secure-docker-blueprint.git
cd secure-docker-blueprint

Nextcloud and Vaultwarden both answer on port 8080: stop one with down before starting the other.

Nextcloud

Files, calendars and contacts on your own server, synced to desktops and phones.

Terminal window
cd apps/nextcloud
cp .env.local.example .env.local
for v in DB_PASSWORD DB_ROOT_PASSWORD REDIS_PASSWORD ADMIN_PASSWORD; do
echo "$v=$(openssl rand -hex 16)"; done >> .env.local
mkdir -p volumes/local/mysql volumes/local/redis volumes/local/html
sudo chown 999:999 volumes/local/mysql
docker compose -f docker-compose.local.yml --env-file .env.local up -d

Open http://localhost:8080 and log in as admin; grep '^ADMIN_PASSWORD=.' .env.local prints the password. Nextcloud guide →

Vaultwarden

Credentials in one vault, synced to browser, phone and desktop.

Terminal window
cd apps/vaultwarden
cp .env.local.example .env.local
for v in DB_PASSWORD DB_ROOT_PASSWORD; do
echo "$v=$(openssl rand -hex 16)"; done >> .env.local
docker compose -f docker-compose.local.yml --env-file .env.local up -d

Open http://localhost:8080 and create an account. Vaultwarden guide →

Immich

Photo and video backup from phones, searchable by what is in the picture.

Terminal window
cd apps/immich
cp .env.local.example .env.local
echo "DB_PASSWORD=$(openssl rand -hex 16)" >> .env.local
mkdir -p volumes/local/redis
sudo chown 999:999 volumes/local/redis
docker compose -f docker-compose.local.yml --env-file .env.local up -d

Open http://localhost:2283; the first account becomes the administrator. Immich guide →

Paperless-ngx

Scanned paper becoming a searchable archive, via OCR and a consume folder.

Terminal window
cd apps/paperless-ngx
cp .env.local.example .env.local
for v in DB_PASSWORD SECRET_KEY ADMIN_PASSWORD; do
echo "$v=$(openssl rand -hex 16)"; done >> .env.local
mkdir -p volumes/local/redis
sudo chown 999:1000 volumes/local/redis
docker compose -f docker-compose.local.yml --env-file .env.local up -d

Open http://localhost:8000 and log in as admin; grep '^ADMIN_PASSWORD=.' .env.local prints the password. Paperless-ngx guide →

Uptime Kuma

Uptime monitoring with a status page and many notification channels.

Terminal window
cd monitoring/uptime-kuma
cp .env.local.example .env.local
docker compose -f docker-compose.local.yml --env-file .env.local up -d

Open http://localhost:3001, choose SQLite and create the owner account on the first visit. Uptime Kuma guide →

Infrastructure

Traefik terminates TLS and is how a service is reached from outside the host. CrowdSec is the optional layer that watches and blocks.

What every server needs →

Applications

Passwords, files and calendars, invoicing, file sync, document editing — each with installation, verification, backup and updates.

What each one is for →

Operations and recovery

Backups with Borgmatic and the restore that proves them, plus a method for finding which layer is actually broken.

What running this involves →

Security

Firewalls, TLS, credentials, isolation, detection, recovery — what each measure stops, what it does not, and where this blueprint sits in the chain.

The whole chain →

Also here: what self-hosting does not answer — who governs each piece of software, and what still leaves the server anyway.

Each guide opens with its evidence line: Last run on a host with the date and the version that ran, data restored from a backup where that happened, the pinned version with what upstream has released since, and the findings the upstream images carry. The line states facts; it grades nothing.

How to read that line →