Add in cloudflare ddns and restructure repo

This commit is contained in:
James Thompson
2026-05-19 08:30:25 +00:00
parent c546fab5e1
commit 6fb3fc65e4
35 changed files with 132 additions and 131 deletions

View File

@@ -0,0 +1,6 @@
# cloudflare-ddns/.env
# Copy to .env and fill in real values. NEVER commit .env.
CLOUDFLARE_API_TOKEN=__CHANGEME__
DOMAINS=example.org,www.example.org
PROXIED=true

View File

@@ -0,0 +1,34 @@
services:
cloudflare-ddns:
image: favonia/cloudflare-ddns:1
# Prefer "1" or "1.x.y" in production.
#
# - "1" tracks the latest stable release whose major version is 1
# - "1.x.y" pins one specific stable version
# - "latest" moves to each new stable release and may pick up breaking
# changes in a future major release, so it is not recommended in production
# - "edge" tracks the latest unreleased development build
network_mode: host
# Optional. This bypasses network isolation and makes IPv6 easier.
# See "Use IPv6 without sharing the host network".
restart: always
# Restart the updater after reboot
user: "1000:1000"
# Run the updater with specific user and group IDs (in that order).
# You can change the two numbers based on your need.
read_only: true
# Make the container filesystem read-only (optional but recommended)
cap_drop: [all]
# Drop all Linux capabilities (optional but recommended)
security_opt: [no-new-privileges:true]
# Another protection to restrict superuser privileges (optional but recommended)
env_file:
- .env
environment:
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
# Your Cloudflare API token
- DOMAINS=${DOMAINS}
# Your domains (separated by commas)
- PROXIED=${PROXIED:-true}
# Leaning toward using Cloudflare's proxy for these domains (optional)
# Existing DNS records in Cloudflare keep their current proxy statuses

6
services/devbox/.env.example Executable file
View File

@@ -0,0 +1,6 @@
# devbox/.env
# Copy to .env and fill in real values. NEVER commit .env.
DEVBOX_SSH_PORT=46573
DEVBOX_MEM_LIMIT=10g
DEVBOX_SWAP_LIMIT=20g

View File

@@ -0,0 +1,13 @@
services:
devcontainer:
image: devbox-devcontainer
container_name: devcontainer
restart: unless-stopped
ports:
- "${DEVBOX_SSH_PORT:-46573}:2222"
volumes:
- ${STORAGE_PATH}/devbox:/home/devuser
env_file:
- ../.env
mem_limit: ${DEVBOX_MEM_LIMIT:-10g}
memswap_limit: ${DEVBOX_SWAP_LIMIT:-20g}

View File

@@ -0,0 +1,7 @@
Serves the generated MkDocs static output from `../site` using NGINX.
Routing is handled by Traefik with host `docs.${DOMAIN}`.
Deploy flow:
1. Build docs: `make docs`
2. Start container: `make up-docs-site` (or `make up`)

View File

@@ -0,0 +1,20 @@
services:
docs-site:
image: nginx:alpine
container_name: docs-site
restart: unless-stopped
volumes:
- ../site:/usr/share/nginx/html:ro
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.docs-site.entrypoints=websecure"
- "traefik.http.routers.docs-site.rule=Host(`docs.${DOMAIN}`)"
- "traefik.http.routers.docs-site.tls=true"
- "traefik.http.routers.docs-site.tls.certresolver=letsencrypt"
- "traefik.http.services.docs-site.loadbalancer.server.port=80"
networks:
web:
external: true

3
services/gitea/.env.example Executable file
View File

@@ -0,0 +1,3 @@
# gitea/.env
# Copy to .env and fill in real values. NEVER commit .env.
# Add any Gitea-specific secrets here.

View File

@@ -0,0 +1,35 @@
services:
gitea:
image: gitea/gitea:1.24.3
container_name: gitea
restart: always
volumes:
- ${STORAGE_PATH}/gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "222:22"
networks:
- gitea
- web
env_file:
- ../.env
- .env
environment:
- USER_UID=${USER_UID}
- USER_GID=${USER_GID}
- GITEA__database__DB_TYPE=sqlite3
- GITEA__server__ROOT_URL=https://gitea.${DOMAIN}/
- USER=git
- GITEA_CUSTOM=/data/gitea
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.rule=Host(`gitea.${DOMAIN}`)"
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
networks:
gitea:
web:
external: true

View File

@@ -0,0 +1,4 @@
# nextcloud/.env
# Copy to .env and fill in real values. NEVER commit .env.
AIO_PORT=8081

View File

@@ -0,0 +1,27 @@
services:
nextcloud-aio-mastercontainer:
image: ghcr.io/nextcloud-releases/all-in-one:latest
container_name: nextcloud-aio-mastercontainer
restart: always
ports:
- "${AIO_PORT}:8080"
volumes:
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- APACHE_PORT=11000
- NEXTCLOUD_DATADIR=${STORAGE_PATH}/nextcloud
- APACHE_ADDITIONAL_NETWORK=web
networks:
- nextcloud-aio
- web
volumes:
nextcloud_aio_mastercontainer:
networks:
nextcloud-aio:
web:
external: true

View File

@@ -0,0 +1,5 @@
# obsidian/.env
# Copy to .env and fill in real values. NEVER commit .env.
COUCHDB_USER=admin
COUCHDB_PASSWORD=REPLACE_WITH_STRONG_PASSWORD

View File

@@ -0,0 +1 @@
*Note*: When setting up for the first time you need to create the directories for both the etc and the data and make sure they are owned by the same UID as the CouchDB container (default 5984) to avoid permission issues.

View File

@@ -0,0 +1,38 @@
services:
couchdb:
image: couchdb:latest
container_name: obsidian-livesync
restart: unless-stopped
environment:
- COUCHDB_USER=${COUCHDB_USER}
- COUCHDB_PASSWORD=${COUCHDB_PASSWORD}
volumes:
- ${STORAGE_PATH}/obsidian-livesync/data:/opt/couchdb/data
- ${STORAGE_PATH}/obsidian-livesync/local.ini:/opt/couchdb/etc/local.d
ports:
- 5984:5984
labels:
- "traefik.enable=true"
# The Traefik Network
- "traefik.docker.network=web"
# Don't forget to replace 'obsidian-livesync.example.org' with your own domain
- "traefik.http.routers.obsidian-livesync.rule=Host(`obsidian-livesync.${DOMAIN}`)"
# The 'websecure' entryPoint is basically your HTTPS entrypoint. Check the next code snippet if you are encountering problems only; you probably have a working traefik configuration if this is not your first container you are reverse proxying.
- "traefik.http.routers.obsidian-livesync.entrypoints=websecure"
- "traefik.http.routers.obsidian-livesync.service=obsidian-livesync"
- "traefik.http.services.obsidian-livesync.loadbalancer.server.port=5984"
- "traefik.http.routers.obsidian-livesync.tls=true"
# Replace the string 'letsencrypt' with your own certificate resolver
- "traefik.http.routers.obsidian-livesync.tls.certresolver=letsencrypt"
- "traefik.http.middlewares.obsidiancors.headers.accessControlAllowOriginList=app://obsidian.md,capacitor://localhost,http://localhost"
- "traefik.http.middlewares.obsidiancors.headers.accessControlAllowMethods=GET,POST,PUT,DELETE,OPTIONS,HEAD"
- "traefik.http.middlewares.obsidiancors.headers.accessControlAllowHeaders=Authorization,Content-Type,Accept,Origin,X-Requested-With"
- "traefik.http.middlewares.obsidiancors.headers.accessControlAllowCredentials=true"
- "traefik.http.middlewares.obsidiancors.headers.accessControlMaxAge=86400"
- "traefik.http.middlewares.obsidiancors.headers.addVaryHeader=true"
- "traefik.http.routers.obsidian-livesync.middlewares=obsidiancors"
networks:
- web
networks:
web:
external: true

6
services/traefik/.env.example Executable file
View File

@@ -0,0 +1,6 @@
# traefik/.env
# Copy to .env and fill in real values. NEVER commit .env.
TRAEFIK_DASHBOARD_PORT=8080
ACME_EMAIL=letsencrypt@example.com
DASHBOARD_BASIC_AUTH=admin:$$apr1$$changeme$$REPLACE_WITH_HTPASSWD_HASH

View File

@@ -0,0 +1 @@
This is the core proxy that protects my server. It handles SSL termination, routing, and the dashboard for monitoring. I use Traefik's Docker provider to automatically discover services and route traffic based on labels in their `docker-compose.yml` files.

View File

@@ -0,0 +1,52 @@
services:
traefik:
image: traefik:v3.6
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "${TRAEFIK_DASHBOARD_PORT}:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${STORAGE_PATH}/traefik/certs:/certs:rw
- ./dynamic:/dynamic:ro
- ${STORAGE_PATH}/traefik/letsencrypt:/letsencrypt
networks:
- web
security_opt:
- no-new-privileges:true
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=${DASHBOARD_BASIC_AUTH}"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.middlewares=dashboard-auth@docker"
- "traefik.http.routers.dashboard.rule=Host(`dashboard.${DOMAIN}`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
command:
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=web"
- "--api.dashboard=true"
- "--api.insecure=false"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}"
- "--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
- "--metrics.prometheus=true"
- "--accesslog=true"
- "--providers.file.directory=/dynamic"
- "--providers.file.watch=true"
environment:
- DOMAIN=${DOMAIN}
networks:
web:
external: true

View File

@@ -0,0 +1,38 @@
http:
routers:
nextcloud:
rule: 'Host(`nextcloud.{{ env "DOMAIN" }}`)'
entryPoints:
- websecure
service: nextcloud
middlewares:
- nextcloud-chain
tls:
certResolver: letsencrypt
services:
nextcloud:
loadBalancer:
servers:
- url: "http://nextcloud-aio-apache:11000"
middlewares:
nextcloud-secure-headers:
headers:
hostsProxyHeaders:
- X-Forwarded-Host
customRequestHeaders:
X-Forwarded-Proto: https
referrerPolicy: same-origin
nextcloud-dav:
redirectRegex:
regex: "^https://([^/]+)/.well-known/(card|cal)dav"
replacement: "https://${1}/remote.php/dav/"
permanent: true
nextcloud-chain:
chain:
middlewares:
- nextcloud-dav
- nextcloud-secure-headers

View File

@@ -0,0 +1,4 @@
tls:
certificates:
- certFile: /certs/local.crt
keyFile: /certs/local.key

View File

@@ -0,0 +1,17 @@
services:
whoami:
image: traefik/whoami
container_name: whoami
restart: unless-stopped
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.rule=Host(`whoami.${DOMAIN}`)"
- "traefik.http.routers.whoami.tls=true"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
networks:
web:
external: true