feat: Migrate from DuckDNS to Porkbun and add Wg-easy
This commit is contained in:
42
README.md
42
README.md
@@ -7,12 +7,12 @@ This repository contains the configuration for my personal homelab stack, includ
|
|||||||
| **Vaultwarden** | Self-hosted password manager (Bitwarden-compatible) | `https://vault.example.com` |
|
| **Vaultwarden** | Self-hosted password manager (Bitwarden-compatible) | `https://vault.example.com` |
|
||||||
| **2FAuth** | Self-hosted two-factor authentication manager | `https://auth.example.com` |
|
| **2FAuth** | Self-hosted two-factor authentication manager | `https://auth.example.com` |
|
||||||
| **Filebrowser** | Self-hosted file hosting service | `https://storage.example.com` |
|
| **Filebrowser** | Self-hosted file hosting service | `https://storage.example.com` |
|
||||||
| **Caddy** | Reverse proxy with automatic HTTPS via DuckDNS (DNS-01) | *No direct UI* |
|
| **Wg-easy** | Wireguard VPN with management console | `https://vpn.example.com` |
|
||||||
|
| **Caddy** | Reverse proxy with automatic HTTPS | *No direct UI* |
|
||||||
| **Portainer** | Makes Docker life 100x easier (visual container manager) | `https://<SERVER_IP>:9443` |
|
| **Portainer** | Makes Docker life 100x easier (visual container manager) | `https://<SERVER_IP>:9443` |
|
||||||
| **Uptime Kuma** | Monitors homelab/domain uptime | `http://<SERVER_IP>:3001` |
|
| **Uptime Kuma** | Monitors homelab/domain uptime | `http://<SERVER_IP>:3001` |
|
||||||
| **Dozzle** | Displays logs super easily (real-time Docker logs) | `http://<SERVER_IP>:9999` |
|
| **Dozzle** | Displays logs super easily (real-time Docker logs) | `http://<SERVER_IP>:9999` |
|
||||||
| **Netdata** | Beautiful system and container monitoring | `http://<SERVER_IP>:19999` |
|
| **Netdata** | Beautiful system and container monitoring | `http://<SERVER_IP>:19999` |
|
||||||
| **DuckDNS Updater** | Updates current dynamic IP address automatically | Runs from `./duckdns/duck.sh` |
|
|
||||||
|
|
||||||
The setup is built with Docker Compose and is designed to be simple, secure, and easy to maintain.
|
The setup is built with Docker Compose and is designed to be simple, secure, and easy to maintain.
|
||||||
|
|
||||||
@@ -20,51 +20,43 @@ The setup is built with Docker Compose and is designed to be simple, secure, and
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
.
|
.
|
||||||
├── duckdns
|
├── porkbun
|
||||||
│ ├── duck.log # Log file for DuckDNS updates
|
│ └── porkbun_ddns.sh # Porkbun DDNS update script (runs via cron)
|
||||||
│ └── duck.sh # DuckDNS update script (runs via cron)
|
|
||||||
└── homelab
|
└── homelab
|
||||||
├── Caddyfile # Reverse proxy configuration for Caddy
|
├── Caddyfile # Reverse proxy configuration for Caddy
|
||||||
└── compose.yml # Docker Compose stack for all services
|
└── compose.yml # Docker Compose stack for all services
|
||||||
```
|
```
|
||||||
|
|
||||||
## Secrets and Environment Variables
|
## Secrets and Environment Variables
|
||||||
|
|
||||||
Before deploying, you **must** replace all placeholder values in the config files.
|
Before deploying, you **must** replace all placeholder values in the config files. See `.env.example`.
|
||||||
|
|
||||||
- `https://vault.example.com` and `vault.example.com` → your Vaultwarden domain
|
## Porkbun Dynamic DNS Updater
|
||||||
- `https://auth.example.com` and `auth.example.com` → your 2FAuth domain
|
|
||||||
- `https://storage.example.com` and `storage.example.com` → your Filebrowser 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 script updates all Porkbun domains used by the homelab.
|
||||||
|
|
||||||
The `duckdns/duck.sh` script updates all DuckDNS domains used by the homelab. It always logs to `duckdns/duck.log`.
|
|
||||||
|
|
||||||
### Run manually
|
### Run manually
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd duckdns
|
cd porkbun
|
||||||
./duck.sh
|
./porkbun_ddns.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cron to run periodically (recommended)
|
### Cron to run periodically (recommended)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd duckdns
|
cd porkbun
|
||||||
chmod 700 duck.sh
|
chmod 700 porkbun_ddns.sh
|
||||||
crontab -e
|
crontab -e
|
||||||
```
|
```
|
||||||
|
|
||||||
Add:
|
Add:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
*/5 * * * * /path/to/duckdns/duck.sh >/dev/null 2>&1
|
*/5 * * * * /path/to/porkbun/porkbun_ddns.sh >/dev/null 2>&1
|
||||||
```
|
```
|
||||||
|
|
||||||
This ensures your DuckDNS domains always point to your current IP.
|
This ensures your Porkbun domains always point to your current IP.
|
||||||
|
|
||||||
## Homelab Stack (Docker Compose)
|
## Homelab Stack (Docker Compose)
|
||||||
|
|
||||||
@@ -75,6 +67,7 @@ The **homelab/** folder contains:
|
|||||||
- `https://<vault-domain>` → Vaultwarden
|
- `https://<vault-domain>` → Vaultwarden
|
||||||
- `https://<auth-domain>` → 2FAuth
|
- `https://<auth-domain>` → 2FAuth
|
||||||
- `https://<storage-domain>` → Filebrowser
|
- `https://<storage-domain>` → Filebrowser
|
||||||
|
- `https://<vpn-domain>` → Wireguard
|
||||||
|
|
||||||
### Start the stack
|
### Start the stack
|
||||||
|
|
||||||
@@ -91,7 +84,8 @@ mkdir -p services/vaultwarden \
|
|||||||
services/netdata/cache \
|
services/netdata/cache \
|
||||||
services/filebrowser/srv \
|
services/filebrowser/srv \
|
||||||
services/filebrowser/database \
|
services/filebrowser/database \
|
||||||
services/filebrowser/config
|
services/filebrowser/config \
|
||||||
|
services/wg-easy/data
|
||||||
ex```
|
ex```
|
||||||
|
|
||||||
### Stop the stack
|
### Stop the stack
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# === CONFIGURATION ===
|
|
||||||
TOKEN="TOKEN"
|
|
||||||
DOMAINS=("auth" "vault" "storage")
|
|
||||||
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"
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
VAULT_DOMAIN=vault.example.com
|
VAULT_DOMAIN=vault.example.com
|
||||||
AUTH_DOMAIN=auth.example.com
|
AUTH_DOMAIN=auth.example.com
|
||||||
STORAGE_DOMAIN=storage.example.com
|
STORAGE_DOMAIN=storage.example.com
|
||||||
|
VPN_DOMAIN=vpn.example.com
|
||||||
EMAIL=mail@example.com
|
EMAIL=mail@example.com
|
||||||
APP_KEY=32characterslongrandomstring!
|
TWOFAUTH_APP_KEY=32characterslongrandomstring!
|
||||||
NC_ADMIN_USER=admin
|
WG_EASY_PASSWORD_HASH=your_bcrypt_hashed_password
|
||||||
NC_ADMIN_PASS=changeme
|
PORKBUN_API_KEY=your_porkbun_api_key
|
||||||
DUCKDNS_TOKEN=TOKEN
|
PORKBUN_API_SECRET=your_porkbun_api_secret
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
# ===========================
|
# ===========================
|
||||||
# DuckDNS
|
# Porkbun
|
||||||
# ===========================
|
# ===========================
|
||||||
(dns_duck) {
|
(dns_porkbun) {
|
||||||
tls {
|
tls {
|
||||||
dns duckdns {env.DUCKDNS_TOKEN}
|
dns porkbun {
|
||||||
|
api_key {env.PORKBUN_API_KEY}
|
||||||
|
api_secret_key {env.PORKBUN_API_SECRET}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
log {
|
log {
|
||||||
output file {env.LOG_FILE}
|
output file {env.LOG_FILE}
|
||||||
@@ -15,10 +18,9 @@
|
|||||||
# Vaultwarden
|
# Vaultwarden
|
||||||
# ===========================
|
# ===========================
|
||||||
{env.VAULT_DOMAIN} {
|
{env.VAULT_DOMAIN} {
|
||||||
import dns_duck
|
import dns_porkbun
|
||||||
|
|
||||||
encode zstd gzip
|
|
||||||
|
|
||||||
|
encode gzip
|
||||||
reverse_proxy vaultwarden:80
|
reverse_proxy vaultwarden:80
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,10 +28,9 @@
|
|||||||
# 2FAuth
|
# 2FAuth
|
||||||
# ===========================
|
# ===========================
|
||||||
{env.AUTH_DOMAIN} {
|
{env.AUTH_DOMAIN} {
|
||||||
import dns_duck
|
import dns_porkbun
|
||||||
|
|
||||||
encode zstd gzip
|
|
||||||
|
|
||||||
|
encode gzip
|
||||||
reverse_proxy 2fauth:8000
|
reverse_proxy 2fauth:8000
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +38,20 @@
|
|||||||
# Filebrowser
|
# Filebrowser
|
||||||
# ===========================
|
# ===========================
|
||||||
{env.STORAGE_DOMAIN} {
|
{env.STORAGE_DOMAIN} {
|
||||||
import dns_duck
|
import dns_porkbun
|
||||||
|
|
||||||
encode zstd gzip
|
|
||||||
|
|
||||||
|
encode gzip
|
||||||
reverse_proxy filebrowser:80
|
reverse_proxy filebrowser:80
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ===========================
|
||||||
|
# WireGuard VPN
|
||||||
|
# ===========================
|
||||||
|
{env.VPN_DOMAIN} {
|
||||||
|
import dns_porkbun
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
tls internal
|
||||||
|
reverse_proxy wg-easy:51821
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Build Caddy with DuckDNS DNS provider
|
# Build Caddy with Porkbun DNS provider
|
||||||
FROM caddy:latest-builder AS builder
|
FROM caddy:latest-builder AS builder
|
||||||
|
|
||||||
RUN xcaddy build \
|
RUN xcaddy build \
|
||||||
--with github.com/caddy-dns/duckdns
|
--with github.com/caddy-dns/porkbun
|
||||||
|
|
||||||
FROM caddy:latest
|
FROM caddy:latest
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ services:
|
|||||||
- ./services/vaultwarden:/data
|
- ./services/vaultwarden:/data
|
||||||
environment:
|
environment:
|
||||||
DOMAIN: "https://${VAULT_DOMAIN}"
|
DOMAIN: "https://${VAULT_DOMAIN}"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
# ==========================
|
# ==========================
|
||||||
# 2FAuth (2FA manager)
|
# 2FAuth (2FA manager)
|
||||||
@@ -26,12 +28,14 @@ services:
|
|||||||
APP_DEBUG: false
|
APP_DEBUG: false
|
||||||
APP_TIMEZONE: UTC
|
APP_TIMEZONE: UTC
|
||||||
SITE_OWNER: ${EMAIL}
|
SITE_OWNER: ${EMAIL}
|
||||||
APP_KEY: ${APP_KEY}
|
APP_KEY: ${TWOFAUTH_APP_KEY}
|
||||||
APP_URL: "https://${AUTH_DOMAIN}"
|
APP_URL: "https://${AUTH_DOMAIN}"
|
||||||
ASSET_URL: "https://${AUTH_DOMAIN}"
|
ASSET_URL: "https://${AUTH_DOMAIN}"
|
||||||
TRUSTED_PROXIES: '*'
|
TRUSTED_PROXIES: '*'
|
||||||
LOG_CHANNEL: daily
|
LOG_CHANNEL: daily
|
||||||
LOG_LEVEL: notice
|
LOG_LEVEL: notice
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
# ==========================
|
# ==========================
|
||||||
# Filebrowser (Cloud file manager)
|
# Filebrowser (Cloud file manager)
|
||||||
@@ -45,6 +49,33 @@ services:
|
|||||||
- ./services/filebrowser/database:/database
|
- ./services/filebrowser/database:/database
|
||||||
- ./services/filebrowser/config:/config
|
- ./services/filebrowser/config:/config
|
||||||
user: "1000:1000"
|
user: "1000:1000"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
|
# ==========================
|
||||||
|
# WG-Easy (WireGuard VPN)
|
||||||
|
# ==========================
|
||||||
|
wg-easy:
|
||||||
|
image: ghcr.io/wg-easy/wg-easy:latest
|
||||||
|
container_name: wg-easy
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
WG_HOST: ${VPN_DOMAIN}
|
||||||
|
PASSWORD_HASH: ${WG_EASY_PASSWORD_HASH}
|
||||||
|
volumes:
|
||||||
|
- ./services/wg-easy/data:/etc/wireguard
|
||||||
|
- /lib/modules:/lib/modules:ro
|
||||||
|
ports:
|
||||||
|
- "51820:51820/udp"
|
||||||
|
- "51821:51821/tcp"
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- SYS_MODULE
|
||||||
|
sysctls:
|
||||||
|
- net.ipv4.ip_forward=1
|
||||||
|
- net.ipv4.conf.all.src_valid_mark=1
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
# ==========================
|
# ==========================
|
||||||
# Caddy (Reverse proxy)
|
# Caddy (Reverse proxy)
|
||||||
@@ -68,9 +99,13 @@ services:
|
|||||||
VAULT_DOMAIN: ${VAULT_DOMAIN}
|
VAULT_DOMAIN: ${VAULT_DOMAIN}
|
||||||
AUTH_DOMAIN: ${AUTH_DOMAIN}
|
AUTH_DOMAIN: ${AUTH_DOMAIN}
|
||||||
STORAGE_DOMAIN: ${STORAGE_DOMAIN}
|
STORAGE_DOMAIN: ${STORAGE_DOMAIN}
|
||||||
|
VPN_DOMAIN: ${VPN_DOMAIN}
|
||||||
EMAIL: ${EMAIL}
|
EMAIL: ${EMAIL}
|
||||||
DUCKDNS_TOKEN: ${DUCKDNS_TOKEN}
|
PORKBUN_API_KEY: ${PORKBUN_API_KEY}
|
||||||
|
PORKBUN_API_SECRET: ${PORKBUN_API_SECRET}
|
||||||
LOG_FILE: /data/access.log
|
LOG_FILE: /data/access.log
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
# ==========================
|
# ==========================
|
||||||
# Portainer (Docker manager)
|
# Portainer (Docker manager)
|
||||||
|
|||||||
27
porkbun/porkbun_ddns.sh
Executable file
27
porkbun/porkbun_ddns.sh
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
API_KEY="pk1_someapikeyvalue1234567890abcdef"
|
||||||
|
API_SECRET="sk1_somesecretapikeyvalueabcdef1234567890"
|
||||||
|
DOMAIN="example.com"
|
||||||
|
SUBDOMAINS=(
|
||||||
|
"vault"
|
||||||
|
"auth"
|
||||||
|
"cloud"
|
||||||
|
"vpn"
|
||||||
|
)
|
||||||
|
|
||||||
|
TTL="600"
|
||||||
|
# =================
|
||||||
|
|
||||||
|
IP="$(curl -fs https://api.ipify.org)"
|
||||||
|
|
||||||
|
for SUBDOMAIN in "${SUBDOMAINS[@]}"; do
|
||||||
|
curl -fs "https://api.porkbun.com/api/json/v3/dns/editByNameType/${DOMAIN}/A/${SUBDOMAIN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"apikey\": \"${API_KEY}\",
|
||||||
|
\"secretapikey\": \"${API_SECRET}\",
|
||||||
|
\"content\": \"${IP}\",
|
||||||
|
\"ttl\": \"${TTL}\"
|
||||||
|
}"
|
||||||
|
done
|
||||||
Reference in New Issue
Block a user