diff options
| author | Max Bossing <info@maxbossing.de> | 2025-09-30 18:02:29 +0200 |
|---|---|---|
| committer | Max Bossing <info@maxbossing.de> | 2025-09-30 18:02:29 +0200 |
| commit | 91a45232bd36727dca2e7474005e240d518d4c54 (patch) | |
| tree | 98fac5162ac356123716634284aece8c927f8106 | |
init
| -rw-r--r-- | README | 7 | ||||
| -rw-r--r-- | scripts/git-backup/README | 10 | ||||
| -rwxr-xr-x | scripts/git-backup/backup.sh | 21 | ||||
| -rw-r--r-- | services/calibre/compose.yaml | 30 | ||||
| -rw-r--r-- | services/directus/compose.yaml | 85 | ||||
| -rw-r--r-- | services/dockge/compose.yaml | 29 | ||||
| -rw-r--r-- | services/etherpad/compose.yaml | 62 | ||||
| -rw-r--r-- | services/forge/compose.yaml | 51 | ||||
| -rw-r--r-- | services/outline/.env | 35 | ||||
| -rw-r--r-- | services/outline/compose.yaml | 64 | ||||
| -rw-r--r-- | services/pocket-id/compose.yaml | 37 | ||||
| -rw-r--r-- | services/traefik/compose.yaml | 32 | ||||
| -rw-r--r-- | services/traefik/config.yaml | 11 | ||||
| -rw-r--r-- | services/traefik/traefik.yaml | 38 |
14 files changed, 512 insertions, 0 deletions
@@ -0,0 +1,7 @@ +This is my infrastructure + +It consists of multiple machines running different things: +- A raspberry pi with Stock HomeAssistantOS and a Zigbee Stick +- A MacBook Air 2015 running Fedora Linux for small background workloads +- A HP ProLiant DL360 G7 with random parts I found for things that need a lot of computing (only turned on sporadically) +- A Debian VPS for public-facing services. diff --git a/scripts/git-backup/README b/scripts/git-backup/README new file mode 100644 index 0000000..aacf691 --- /dev/null +++ b/scripts/git-backup/README @@ -0,0 +1,10 @@ +* git-backup - backup script + +This simply copies all git repositories from my git forge (git.c41ro.win) to my local server. + +1. Drop this script in /opt/git-backup/ and make it executable. +2. Create a new ssh keypair and put the private key under /opt/git-backup/ssh-key (this file needs to have 0600 permissions). +3. Add a new cron job like this `@daily /opt/git-backup/backup.sh >> /opt/git-backup/backup.sh`. + + +License: It's like 10 lines bro. MIT if you must. diff --git a/scripts/git-backup/backup.sh b/scripts/git-backup/backup.sh new file mode 100755 index 0000000..320cb3b --- /dev/null +++ b/scripts/git-backup/backup.sh @@ -0,0 +1,21 @@ +#!/usr/bin/bash + +# backup.sh - backup git repositories from somewhere else to local + +BACKUP_TIME="$(date +'%Y-%m-%dT%H:%M:%S')" +BACKUP_DIR="/opt/git-backup/backup" + +REPO_LOCATION="/opt/soft-serve/repos" + +SSH_KEY_LOCATION="/opt/git-backup/ssh-key" +SSH_USER="bossing" +SSH_HOST="c41ro.win" +SSH_PORT="47" + +echo "Starting backup at $BACKUP_TIME" + +mkdir -p "$BACKUP_DIR/$BACKUP_TIME" + +scp -i "$SSH_KEY_LOCATION" -P "$SSH_PORT" -r "$SSH_USER"@"$SSH_HOST":"$REPO_LOCATION"/* "$BACKUP_DIR/$BACKUP_TIME" + +echo "Backup finished at $(date +'%Y-%m-%dT%H:%M:%S')" diff --git a/services/calibre/compose.yaml b/services/calibre/compose.yaml new file mode 100644 index 0000000..082e1ae --- /dev/null +++ b/services/calibre/compose.yaml @@ -0,0 +1,30 @@ +networks: + proxy: + external: true + +volumes: + data: + +services: + calibre-web: + image: lscr.io/linuxserver/calibre-web:latest + container_name: calibre-web + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin + - DOCKER_MODS=linuxserver/mods:universal-calibre + - OAUTHLIB_RELAX_TOKEN_SCOPE=1 + volumes: + - data:/config + - /opt/media/books:/books:Z + networks: + - proxy + labels: + traefik.enable: true + traefik.http.services.calibre.loadbalancer.server.port: 8083 + traefik.http.routers.calibre.rule: Host(`calibre.4d6178.work`) + traefik.http.routers.calibre.entrypoints: websecure + traefik.http.routers.calibre.tls: true + traefik.http.routers.calibre.tls.certresolver: le + restart: unless-stopped diff --git a/services/directus/compose.yaml b/services/directus/compose.yaml new file mode 100644 index 0000000..7006049 --- /dev/null +++ b/services/directus/compose.yaml @@ -0,0 +1,85 @@ +networks: + default: + proxy: + external: true + +volumes: + postgis: + uploads: + extensions: + +services: + postgis: + image: postgis/postgis:13-master + container_name: directus-postgis + volumes: + - postgis:/var/lib/postgresql/data + environment: + POSTGRES_USER: directus + POSTGRES_PASSWORD: directus + POSTGRES_DB: directus + healthcheck: + test: + - CMD + - pg_isready + - --host=localhost + - --username=directus + interval: 10s + timeout: 5s + retries: 5 + start_interval: 5s + start_period: 30s + networks: + - default + + redis: + image: redis:6 + container_name: directus-redis + healthcheck: + test: + - CMD-SHELL + - "[ $$(redis-cli ping) = 'PONG' ]" + interval: 10s + timeout: 5s + retries: 5 + start_interval: 5s + start_period: 30s + networks: + - default + + directus: + image: directus/directus:latest + container_name: directus + labels: + traefik.enable: true + traefik.http.services.directus.loadbalancer.server.port: 8055 + traefik.http.routers.directus.rule: Host(`directus.4d6178.work`) + traefik.http.routers.directus.entrypoints: websecure + traefik.http.routers.directus.tls: true + traefik.http.routers.directus.tls.certresolver: le + volumes: + - uploads:/directus/uploads + - extensions:/directus/extensions + depends_on: + postgis: + condition: service_healthy + redis: + condition: service_healthy + networks: + - proxy + - default + environment: + SECRET: + DB_CLIENT: pg + DB_HOST: postgis + DB_PORT: "5432" + DB_DATABASE: directus + DB_USER: directus + DB_PASSWORD: directus + CACHE_ENABLED: "true" + CACHE_AUTO_PURGE: "true" + CACHE_STORE: redis + REDIS: redis://redis:6379 + ADMIN_EMAIL: admin@4d6178.work + ADMIN_PASSWORD: + PUBLIC_URL: https://directus.4d6178.work diff --git a/services/dockge/compose.yaml b/services/dockge/compose.yaml new file mode 100644 index 0000000..3d5a915 --- /dev/null +++ b/services/dockge/compose.yaml @@ -0,0 +1,29 @@ +networks: + proxy: + external: true + +volumes: + data: + +services: + dockge: + image: louislam/dockge:1 + container_name: dockge + restart: unless-stopped + labels: + - traefik.enable=true + - traefik.http.routers.dockge.service=dockge + - traefik.http.services.dockge.loadbalancer.server.port=5001 + - traefik.http.routers.dockge.rule=Host(`dockge.4d6178.work`) + - traefik.http.routers.dockge.entrypoints=websecure + - traefik.http.routers.dockge.tls=true + - traefik.http.routers.dockge.tls.certresolver=le + - traefik.http.routers.dockge.middlewares=oidc-auth@file + networks: + - proxy + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - data:/app/data + - /opt/stacks:/opt/stacks + environment: + - DOCKGE_STACKS_DIR=/opt/stacks diff --git a/services/etherpad/compose.yaml b/services/etherpad/compose.yaml new file mode 100644 index 0000000..831723d --- /dev/null +++ b/services/etherpad/compose.yaml @@ -0,0 +1,62 @@ +volumes: + postgres: + plugins: + data: + +networks: + proxy: + external: true + default: + +services: + etherpad: + user: "0:0" + image: etherpad/etherpad:latest + container_name: etherpad + tty: true + stdin_open: true + volumes: + - plugins:/opt/etherpad-lite/src/plugin_packages + - data:/opt/etherpad-lite/var + depends_on: + - postgres + labels: + traefik.enable: true + traefik.port: 9001 + traefik.http.routers.etherpad.rule: Host(`etherpad.4d6178.work`) + traefik.http.routers.etherpad.entrypoints: websecure + traefik.http.routers.etherpad.tls: true + traefik.http.routers.etherpad.tls.certresolver: le + environment: + NODE_ENV: production + ADMIN_PASSWORD: + DB_CHARSET: utf8mb4 + DB_HOST: postgres + DB_NAME: etherpad + DB_PASS: admin + DB_PORT: 5432 + DB_TYPE: "postgres" + DB_USER: admin + DEFAULT_PAD_TEXT: Hello, World! + DISABLE_IP_LOGGING: true + SOFFICE: null + TRUST_PROXY: null + restart: unless-stopped + networks: + - proxy + - default + + postgres: + image: postgres:15-alpine + container_name: etherpad-postgres + environment: + POSTGRES_DB: etherpad + POSTGRES_PASSWORD: admin + POSTGRES_PORT: 5432 + POSTGRES_USER: admin + PGDATA: /var/lib/postgresql/data/pgdata + restart: unless-stopped + volumes: + - postgres:/var/lib/postgresql/data + networks: + - default diff --git a/services/forge/compose.yaml b/services/forge/compose.yaml new file mode 100644 index 0000000..ea625b8 --- /dev/null +++ b/services/forge/compose.yaml @@ -0,0 +1,51 @@ +networks: + proxy: + external: true + +services: + soft-serve: + image: charmcli/soft-serve:latest + container_name: soft-serve + volumes: + - /opt/soft-serve:/soft-serve + ports: + - 22:23231 + environment: + SOFT_SERVE_INITIAL_ADMIN_KEYS: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC9bbTKjwyLcrAg7v6JoUtHbVu43sgEuHObqnVWBFBQDlktKda+0RkyhPMVM4ReqfnaMJ2U+IwzWiVaf/2gQ2CRACCm+idaPlu/Et3YIAcWtUhc2p8j8YPJqwMpbDwfwMWh7AdeIHS+/QyuFMnbP96/bMFvmli5kcpdL0zAqJ87DwPUqr6s3npM91T0+XExPBV40k93gQOkjVzJLCCRHP7AUkyH1JwQBb+Dg/E6BIv56w34eAhaJ2U0RjjZ1TJHrAhiANRdGreQGk4Pa+I8X85kTe2toEi+b5FvkfewskCeA1Yeo1MJikP2bevPdQAuzfTnqS2IacMBbnVcAuGFO5EahwPp1S3Kxgkhk5iSvTQ1kwd07Xoo12zFeV7eNvu/6lvJWiAFE5ZqQ5Ri/MoSQyxrlLkQxkWCcrXYUL6Bxm/kKU3+pHL/9DmEs71t2P9AqXtyBKTqtdhsKzDSFw4cxzaJ8Ygxop5C4SYdI6i2+guw992ojMEcTNHa7cgFbNvRs1dUL7ZxFl4vRtvixOjVXld69ugLmONWUoZB+zb9ptY6DX7v2fR3bRuW5hgzhua/jci8DhV3mkvhJPILtqjx+yDNEfOrYoPzQrhDGb4+hru/6i2r/b+zAfE2Fsd3B443UGRBhzbyo9YlQOuZjiTJHUxKhQGJ7QDdbwp6sBgr4LVGnw==" + restart: unless-stopped + + cgit-private: + image: oems/cgit + container_name: cgit-private + restart: unless-stopped + volumes: + - /opt/soft-serve/repos:/mnt/git + networks: + - proxy + labels: + - traefik.enable=true + - traefik.http.routers.cgit-private.service=cgit-private + - traefik.http.services.cgit-private.loadbalancer.server.port=80 + - traefik.http.routers.cgit-private.rule=Host(`git.c41ro.win`) + - traefik.http.routers.cgit-private.entrypoints=websecure + - traefik.http.routers.cgit-private.tls=true + - traefik.http.routers.cgit-private.tls.certresolver=le + - traefik.http.routers.cgit-private.middlewares=oidc-auth@file + + cgit-pub: + image: oems/cgit + container_name: cgit-pub + restart: unless-stopped + volumes: + - /opt/soft-serve/repos/public:/mnt/git + networks: + - proxy + labels: + - traefik.enable=true + - traefik.http.routers.cgit-pub.service=cgit-pub + - traefik.http.services.cgit-pub.loadbalancer.server.port=80 + - traefik.http.routers.cgit-pub.rule=Host(`pub.git.c41ro.win`) + - traefik.http.routers.cgit-pub.entrypoints=websecure + - traefik.http.routers.cgit-pub.tls=true + - traefik.http.routers.cgit-pub.tls.certresolver=le + diff --git a/services/outline/.env b/services/outline/.env new file mode 100644 index 0000000..e9ee83c --- /dev/null +++ b/services/outline/.env @@ -0,0 +1,35 @@ +URL=https://outline.4d6178.work +PORT=3000 +WEB_CONCURRENCY=5 + +SECRET_KEY= +UTILS_SECRET= + +DEFAULT_LANGUAGE=en_GB + +DATABASE_URL=postgres://outline:outline@postgres:5432/outline +PGSSLMODE=disable +REDIS_URL=redis://redis:6379 + +FILE_STORAGE=local +FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data +FILE_STORAGE_UPLOAD_MAX_SIZE=262144000 + +FORCE_HTTPS=false + +OIDC_CLIENT_ID= +OIDC_CLIENT_SECRET= +OIDC_AUTH_URI=https://id.4d6178.work/authorize +OIDC_TOKEN_URI=https://id.4d6178.work/api/oidc/token +OIDC_USERINFO_URI=https://id.4d6178.work/api/oidc/userinfo +OIDC_LOGOUT_URI=https://id.4d6178.work/api/oidc/end-session +OIDC_USERNAME_CLAIM=preferred_username +OIDC_DISPLAY_NAME=PocketId +OIDC_SCOPES=openid profile email + +RATE_LIMITER_ENABLED=true +RATE_LIMITER_REQUESTS=1000 +RATE_LIMITER_DURATION_WINDOW=60 + +ENABLE_UPDATES=false +LOG_LEVEL=info diff --git a/services/outline/compose.yaml b/services/outline/compose.yaml new file mode 100644 index 0000000..f52a075 --- /dev/null +++ b/services/outline/compose.yaml @@ -0,0 +1,64 @@ +networks: + default: + proxy: + external: true + +volumes: + data: + postgres: + +services: + outline: + image: docker.getoutline.com/outlinewiki/outline:latest + env_file: .env + volumes: + - data:/var/lib/outline/data + networks: + - default + - proxy + labels: + traefik.enable: true + traefik.http.routers.outline.rule: Host(`outline.4d6178.work`) + traefik.http.services.outline.loadbalancer.server.port: 3000 + traefik.http.routers.outline.entrypoints: websecure + traefik.http.routers.outline.tls: true + traefik.http.routers.outline.tls.certresolver: le + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + restart: unless-stopped + + redis: + image: redis + env_file: .env + volumes: + - /opt/outline/redis.conf:/redis.conf + command: ["redis-server", "/redis.conf"] + networks: + - default + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 30s + retries: 3 + restart: unless-stopped + + postgres: + image: postgres + env_file: .env + volumes: + - postgres:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-d", "outline", "-U", "outline"] + interval: 30s + timeout: 20s + retries: 3 + networks: + - default + environment: + POSTGRES_USER: 'outline' + POSTGRES_PASSWORD: 'outline' + POSTGRES_DB: 'outline' + restart: unless-stopped diff --git a/services/pocket-id/compose.yaml b/services/pocket-id/compose.yaml new file mode 100644 index 0000000..8488e47 --- /dev/null +++ b/services/pocket-id/compose.yaml @@ -0,0 +1,37 @@ +networks: + proxy: + external: true + +volumes: + data: + +services: + pocket-id: + image: ghcr.io/pocket-id/pocket-id:v1 + container_name: pocket-id + restart: unless-stopped + labels: + traefik.enable: true + traefik.port: 1411 + traefik.http.routers.pocket-id.rule: Host(`id.4d6178.work`) + traefik.http.routers.pocket-id.entrypoints: websecure + traefik.http.routers.pocket-id.tls: true + traefik.http.routers.pocket-id.tls.certresolver: le + volumes: + - data:/app/data + networks: + - proxy + environment: + APP_URL: https://id.4d6178.work + TRUST_PROXY: true + PUID: 1000 + PGID: 1000 + healthcheck: + test: + - CMD + - /app/pocket-id + - healthcheck + interval: 1m30s + timeout: 5s + retries: 2 + start_period: 10s diff --git a/services/traefik/compose.yaml b/services/traefik/compose.yaml new file mode 100644 index 0000000..504367c --- /dev/null +++ b/services/traefik/compose.yaml @@ -0,0 +1,32 @@ +networks: + proxy: + external: true + +volumes: + acme: + +services: + traefik: + image: traefik + container_name: traefik + restart: always + environment: + CF_DNS_API_TOKEN: + networks: + - proxy + ports: + - 80:80 + - 443:443 + labels: + traefik.enable: true + traefik.http.routers.dashboard.rule: Host(`traefik.4d6178.work`) + traefik.http.routers.dashboard.service: api@internal + traefik.http.routers.dashboard.entrypoints: websecure + traefik.http.routers.dashboard.tls: true + traefik.http.routers.dashboard.tls.certresolver: le + traefik.http.routers.dashboard.middlewares: oidc-auth@file + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - acme:/acme + - /opt/traefik/traefik.yaml:/etc/traefik/traefik.yaml + - /opt/traefik/config.yaml:/etc/traefik/config.yaml diff --git a/services/traefik/config.yaml b/services/traefik/config.yaml new file mode 100644 index 0000000..1e7f78f --- /dev/null +++ b/services/traefik/config.yaml @@ -0,0 +1,11 @@ +http: + middlewares: + oidc-auth: + plugin: + traefik-oidc-auth: + Secret: "" + Provider: + Url: "https://id.4d6178.work" + ClientId: + ClientSecret: + Scopes: ["openid", "email", "profile"] diff --git a/services/traefik/traefik.yaml b/services/traefik/traefik.yaml new file mode 100644 index 0000000..dd1bbe6 --- /dev/null +++ b/services/traefik/traefik.yaml @@ -0,0 +1,38 @@ +entrypoints: + web: + address: ":80" + http: + redirections: + entrypoint: + to: websecure + scheme: https + websecure: + address: ":443" + +providers: + docker: + exposedByDefault: false + network: proxy + file: + filename: /etc/traefik/config.yaml + +certificatesResolvers: + le: + acme: + dnschallenge: + provider: cloudflare + delaybeforecheck: 0 + email: max@bossi.ng + storage: /acme/acme.json + +api: + dashboard: true + +log: + level: DEBUG + +experimental: + plugins: + traefik-oidc-auth: + moduleName: "github.com/sevensolutions/traefik-oidc-auth" + version: "v0.13.0" |
