diff --git a/README.md b/README.md index b966393..16c16ad 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Each stack is independently deployable with its own `compose.yml` and `.env`. Al | `umami` | Web analytics | umami, db | | `immich` | Photo & video management | immich, ml, redis, db | | `blinko` | AI-powered personal notes | blinko, db | -| `mattermost` | Team chat | mattermost, db | +| `n8n` | Workflow automation & notification relay | n8n, db | | `gitea` | Git hosting + CI runner | gitea, runner, db | | `coolify` | Deployment platform | coolify, realtime, redis, db | | `vaultwarden` | Password manager | vaultwarden | @@ -44,7 +44,7 @@ All stacks share the external `falcon_network` Docker network for inter-service ## Backup -The `_backup` stack runs a daily restic backup at 3:00 AM. It dumps all Postgres databases, then backs up the entire `.data/` directory to HiDrive. Retention: 7 daily, 4 weekly, 6 monthly snapshots. Notifications go to Mattermost. +The `_backup` stack runs a daily restic backup at 3:00 AM. It dumps all Postgres databases, then backs up the entire `.data/` directory to HiDrive. Retention: 7 daily, 4 weekly, 6 monthly snapshots. Notifications go to Telegram via n8n. ```bash # Deploy backup stack diff --git a/_backup/.env.example b/_backup/.env.example new file mode 100644 index 0000000..ece9114 --- /dev/null +++ b/_backup/.env.example @@ -0,0 +1,3 @@ +RESTIC_REPOSITORY=/mnt/hidrive/users/valknar/Backup/stacks +RESTIC_PASSWORD=change_me +WEBHOOK_URL=https://n8n.example.com/webhook/change_me diff --git a/_backup/backup.sh b/_backup/backup.sh index 1704f54..1c6974f 100755 --- a/_backup/backup.sh +++ b/_backup/backup.sh @@ -18,9 +18,9 @@ log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; } notify() { local color="$1" text="$2" - curl -sf -o /dev/null -X POST "$MATTERMOST_WEBHOOK" \ + curl -sf -o /dev/null -X POST "$WEBHOOK_URL" \ -H 'Content-Type: application/json' \ - -d "{\"attachments\":[{\"color\":\"$color\",\"text\":\"$text\"}]}" + -d "{\"text\":\"$text\",\"color\":\"$color\"}" } # Truncate log on each run @@ -35,7 +35,7 @@ declare -A DATABASES=( [umami_db]="umami:umami" [blinko_db]="blinko:blinko" [gitea_db]="gitea:gitea" - [mattermost_db]="mattermost:mattermost" + [n8n_db]="n8n:n8n" [immich_db]="immich:immich" [coolify_db]="coolify:coolify" ) diff --git a/mattermost/.env.example b/mattermost/.env.example deleted file mode 100644 index bf1b1c2..0000000 --- a/mattermost/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -TRAEFIK_HOST=mattermost.example.com -NETWORK_NAME=falcon_network diff --git a/mattermost/compose.yml b/mattermost/compose.yml deleted file mode 100644 index 4144b7e..0000000 --- a/mattermost/compose.yml +++ /dev/null @@ -1,67 +0,0 @@ -services: - mattermost: - image: mattermost/mattermost-team-edition:latest - container_name: mattermost - security_opt: - - no-new-privileges:true - pids_limit: 200 - tmpfs: - - /tmp - environment: - TZ: ${TIMEZONE:-Europe/Amsterdam} - MM_SQLSETTINGS_DRIVERNAME: postgres - MM_SQLSETTINGS_DATASOURCE: postgres://mattermost:mattermost@mattermost_db:5432/mattermost?sslmode=disable&connect_timeout=10 - MM_BLEVESETTINGS_INDEXDIR: /mattermost/bleve-indexes - MM_SERVICESETTINGS_SITEURL: https://${TRAEFIK_HOST} - MM_SERVICESETTINGS_ENABLELOCALMODE: "true" - MM_EMAILSETTINGS_ENABLESMTPAUTH: "false" - MM_EMAILSETTINGS_SMTPSERVER: mailpit - MM_EMAILSETTINGS_SMTPPORT: "1025" - MM_EMAILSETTINGS_CONNECTIONSECURITY: "" - MM_EMAILSETTINGS_FEEDBACKNAME: Mattermost - volumes: - - ../.data/mattermost/config:/mattermost/config:rw - - ../.data/mattermost/data:/mattermost/data:rw - - ../.data/mattermost/plugins:/mattermost/plugins:rw - - ../.data/mattermost/client-plugins:/mattermost/client/plugins:rw - - ../.data/mattermost/bleve:/mattermost/bleve-indexes:rw - depends_on: - db: - condition: service_healthy - restart: always - labels: - - "traefik.enable=true" - - "traefik.http.middlewares.mattermost-redirect-web-secure.redirectscheme.scheme=https" - - "traefik.http.routers.mattermost-web.middlewares=mattermost-redirect-web-secure" - - "traefik.http.routers.mattermost-web.rule=Host(`${TRAEFIK_HOST}`)" - - "traefik.http.routers.mattermost-web.entrypoints=web" - - "traefik.http.routers.mattermost-web-secure.rule=Host(`${TRAEFIK_HOST}`)" - - "traefik.http.routers.mattermost-web-secure.tls.certresolver=resolver" - - "traefik.http.routers.mattermost-web-secure.entrypoints=web-secure" - - "traefik.http.routers.mattermost-web-secure.middlewares=security-headers@file,no-index@file" - - "traefik.http.services.mattermost-web-secure.loadbalancer.server.port=8065" - - "traefik.docker.network=${NETWORK_NAME}" - - "com.centurylinklabs.watchtower.enable=true" - networks: - - compose_network - db: - image: postgres:16-alpine - container_name: mattermost_db - environment: - POSTGRES_DB: mattermost - POSTGRES_USER: mattermost - POSTGRES_PASSWORD: mattermost - volumes: - - ../.data/mattermost/db:/var/lib/postgresql/data - restart: always - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] - interval: 5s - timeout: 5s - retries: 5 - networks: - - compose_network -networks: - compose_network: - name: ${NETWORK_NAME} - external: true diff --git a/n8n/.env.example b/n8n/.env.example new file mode 100644 index 0000000..efec9e1 --- /dev/null +++ b/n8n/.env.example @@ -0,0 +1,3 @@ +TRAEFIK_HOST=n8n.example.com +NETWORK_NAME=falcon_network +N8N_ENCRYPTION_KEY=change_me diff --git a/n8n/compose.yml b/n8n/compose.yml new file mode 100644 index 0000000..1374a8e --- /dev/null +++ b/n8n/compose.yml @@ -0,0 +1,59 @@ +services: + n8n: + image: n8nio/n8n:latest + container_name: n8n + environment: + TZ: ${TIMEZONE:-Europe/Amsterdam} + N8N_HOST: ${TRAEFIK_HOST} + N8N_PORT: 5678 + N8N_PROTOCOL: https + WEBHOOK_URL: https://${TRAEFIK_HOST}/ + N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY} + DB_TYPE: postgresdb + DB_POSTGRESDB_HOST: n8n_db + DB_POSTGRESDB_PORT: 5432 + DB_POSTGRESDB_DATABASE: n8n + DB_POSTGRESDB_USER: n8n + DB_POSTGRESDB_PASSWORD: n8n + volumes: + - ../.data/n8n/data:/home/node/.n8n + depends_on: + db: + condition: service_healthy + restart: always + labels: + - "traefik.enable=true" + - "traefik.http.middlewares.n8n-redirect-web-secure.redirectscheme.scheme=https" + - "traefik.http.routers.n8n-web.middlewares=n8n-redirect-web-secure" + - "traefik.http.routers.n8n-web.rule=Host(`${TRAEFIK_HOST}`)" + - "traefik.http.routers.n8n-web.entrypoints=web" + - "traefik.http.routers.n8n-web-secure.rule=Host(`${TRAEFIK_HOST}`)" + - "traefik.http.routers.n8n-web-secure.tls.certresolver=resolver" + - "traefik.http.routers.n8n-web-secure.entrypoints=web-secure" + - "traefik.http.routers.n8n-web-secure.middlewares=security-headers@file,no-index@file" + - "traefik.http.services.n8n-web-secure.loadbalancer.server.port=5678" + - "traefik.docker.network=${NETWORK_NAME}" + - "com.centurylinklabs.watchtower.enable=true" + networks: + - compose_network + db: + image: postgres:16-alpine + container_name: n8n_db + environment: + POSTGRES_DB: n8n + POSTGRES_USER: n8n + POSTGRES_PASSWORD: n8n + volumes: + - ../.data/n8n/db:/var/lib/postgresql/data + restart: always + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] + interval: 5s + timeout: 5s + retries: 5 + networks: + - compose_network +networks: + compose_network: + name: ${NETWORK_NAME} + external: true diff --git a/watchtower/.env.example b/watchtower/.env.example index 0fe4278..2eca7de 100644 --- a/watchtower/.env.example +++ b/watchtower/.env.example @@ -1 +1 @@ -NOTIFICATION_URL=mattermost://mattermost.example.com/change_me +NOTIFICATION_URL=generic+https://n8n.example.com/webhook/change_me