commit bb50bd75afb961caf252db4aa54cd477361831ce Author: Andrew Trieu Date: Sat Nov 15 14:30:39 2025 +0200 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d08079 --- /dev/null +++ b/README.md @@ -0,0 +1,135 @@ +# Homelab Setup (Vaultwarden + 2FAuth + Caddy + DuckDNS) + +This repository contains the configuration for my personal homelab stack, including: + +- **Vaultwarden** – self-hosted password manager (Bitwarden-compatible) +- **2FAuth** – self-hosted two-factor authentication manager +- **Caddy** – reverse proxy with automatic HTTPS via DuckDNS (DNS-01) +- **DuckDNS Updater** – updates my dynamic IP address automatically + +The setup is built with Docker Compose and is designed to be simple, secure, and easy to maintain. + +## Directory Structure + +```bash +. +├── duckdns +│ ├── duck.log # Log file for DuckDNS updates +│ └── duck.sh # DuckDNS update script (runs via cron) +└── homelab + ├── Caddyfile # Reverse proxy configuration for Caddy + └── compose.yml # Docker Compose stack for Vaultwarden + 2FAuth + Caddy +``` + +## Secrets and Environment Variables + +Before deploying, you **must** replace all placeholder values in the config files. + +- `https://vault.example.com` and `vault.example.com` → your Vaultwarden domain +- `https://auth.example.com` and `auth.example.com` → your 2FAuth domain +- `admin@example.com` → your email address (used by Caddy / Let’s Encrypt and 2FAuth) +- `TOKEN` → your DuckDNS token +- `SomeRandomStringOf32CharsExactly` → a **32-character** random string for `APP_KEY` + +## DuckDNS Dynamic DNS Updater + +The `duckdns/duck.sh` script updates all DuckDNS domains used by the homelab. It always logs to `duckdns/duck.log`. + +### Run manually + +```bash +cd duckdns +./duck.sh +``` + +### Cron to run periodically (recommended) + +```bash +cd duckdns +chmod 700 duck.sh +crontab -e +``` + +Add: + +```bash +*/5 * * * * /path/to/duckdns/duck.sh >/dev/null 2>&1 +``` + +This ensures your DuckDNS domains always point to your current IP. + +## Homelab Stack (Docker Compose) + +The **homelab/** folder contains: + +- `compose.yml` – runs Vaultwarden, 2FAuth, and Caddy +- `Caddyfile` – defines routing for: + - `https://` → Vaultwarden + - `https://` → 2FAuth + +### Start the stack + +```bash +cd homelab +docker compose up -d +``` + +### Stop the stack + +```bash +cd homelab +docker compose down +``` + +### View logs + +```bash +docker logs caddy -f +docker logs vaultwarden -f +docker logs 2fauth -f +``` + +### Auto-start on system boot + +The containers already use: + +```yml +restart: always +``` + +But remember to enable Docker on startup: + +```bash +sudo systemctl enable docker +``` + +### Set correct permissions for volumes (optional) + +Run: + +```bash +sudo chown -R 1000:1000 homelab/vaultwarden +sudo chmod -R 755 homelab/vaultwarden + +sudo chown -R 1000:1000 homelab/2fauth +sudo chmod -R 755 homelab/2fauth +``` + +Then restart the containers: + +```bash +cd homelab +docker compose restart vaultwarden 2fauth +``` + +## Updating + +To update to the latest versions: + +```bash +cd homelab +docker compose pull +docker compose up -d +``` + +This will refresh all Docker images with zero downtime. diff --git a/duckdns/duck.log b/duckdns/duck.log new file mode 100644 index 0000000..870fdb9 --- /dev/null +++ b/duckdns/duck.log @@ -0,0 +1,5 @@ +OKUpdating DuckDNS domain andy-auth: +OK +Updating DuckDNS domain andy-vault: +OK +DuckDNS update completed at Sat Nov 15 02:05:38 PM EET 2025 diff --git a/duckdns/duck.sh b/duckdns/duck.sh new file mode 100755 index 0000000..c4fe0d3 --- /dev/null +++ b/duckdns/duck.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# === CONFIGURATION === +TOKEN="TOKEN" +DOMAINS=("auth" "vault") +LOG_DIR="$(cd "$(dirname "$0")" && pwd)" +LOG_FILE="$LOG_DIR/duck.log" + +# === SETUP === +mkdir -p "$LOG_DIR" + +# === UPDATE ALL DOMAINS === +for domain in "${DOMAINS[@]}"; do + echo "Updating DuckDNS domain $domain:" >> "$LOG_FILE" + curl -ks "https://www.duckdns.org/update?domains=${domain}&token=${TOKEN}&ip=" >> "$LOG_FILE" + echo "" >> "$LOG_FILE" +done + +echo "DuckDNS update completed at $(date)" >> "$LOG_FILE" diff --git a/homelab/Caddyfile b/homelab/Caddyfile new file mode 100644 index 0000000..ac713e0 --- /dev/null +++ b/homelab/Caddyfile @@ -0,0 +1,41 @@ +# =========================== +# Vaultwarden +# =========================== +{$VAULT_DOMAIN} { + log { + level INFO + output file {$LOG_FILE} { + roll_size 10MB + roll_keep 10 + } + } + + tls { + dns duckdns {$DUCKDNS_TOKEN} + } + + encode zstd gzip + + reverse_proxy vaultwarden:80 +} + +# =========================== +# 2FAuth +# =========================== +{$AUTH_DOMAIN} { + log { + level INFO + output file {$LOG_FILE} { + roll_size 10MB + roll_keep 10 + } + } + + tls { + dns duckdns {$DUCKDNS_TOKEN} + } + + encode zstd gzip + + reverse_proxy 2fauth:8000 +} diff --git a/homelab/compose.yml b/homelab/compose.yml new file mode 100644 index 0000000..bf39b94 --- /dev/null +++ b/homelab/compose.yml @@ -0,0 +1,55 @@ +services: + vaultwarden: + image: vaultwarden/server:latest + container_name: vaultwarden + restart: always + volumes: + - ./vaultwarden:/data + environment: + DOMAIN: "https://vault.example.com" # Change to yours + + 2fauth: + image: 2fauth/2fauth:latest + container_name: 2fauth + restart: always + volumes: + - ./2fauth:/data + environment: + - APP_NAME=2FAuth + - APP_ENV=production + - APP_DEBUG=false + - APP_TIMEZONE=Europe/Helsinki + - SITE_OWNER=admin@example.com # Change to yours + - APP_KEY=SomeRandomStringOf32CharsExactly # Change to yours + - APP_URL=https://auth.example.com # Change to yours + - ASSET_URL=https://auth.example.com # Change to yours + - TRUSTED_PROXIES=* + - LOG_CHANNEL=daily + - LOG_LEVEL=notice + networks: + - default + + caddy: + image: caddy:2 + container_name: caddy + restart: always + ports: + - 80:80 + - 443:443 + - 443:443/udp + volumes: + - ./caddy:/usr/bin/caddy + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - ./caddy-config:/config + - ./caddy-data:/data + environment: + # For Caddy: hostnames only, no https:// + VAULT_DOMAIN: "vault.example.com" # Change to yours + AUTH_DOMAIN: "auth.example.com" # Change to yours + EMAIL: "admin@example.com" # Change to yours + DUCKDNS_TOKEN: "TOKEN" # Change to yours + LOG_FILE: "/data/access.log" + +networks: + default: + driver: bridge