Merge branch 'main' into codex/enhance-docker-security-configurations

This commit is contained in:
beatz174-bit
2026-04-07 22:04:32 +10:00
committed by GitHub
23 changed files with 378 additions and 152 deletions
+9
View File
@@ -0,0 +1,9 @@
# Copy this file to default-environment.env (non-secret defaults) and update values.
PROJECT_ROOT=/path/to/docker
DOMAIN=example.com
TZ=Etc/UTC
EMAIL=admin@example.com
# Required secret file path used by compose services.
# Create this file from secrets/.env.secrets.example and keep it out of git.
SECRETS_ENV_FILE=${PROJECT_ROOT}/secrets/stack-secrets.env
+3 -1
View File
@@ -21,4 +21,6 @@ apps/searxng/*
venv/ venv/
core/authelia/users_database.yml core/authelia/users_database.yml
monitoring/influxdb/* monitoring/influxdb/*
secrets/*
!secrets/.env.secrets.example
!.env.example
+49
View File
@@ -0,0 +1,49 @@
# Deployment prerequisites (required)
Before running `docker compose up`, you **must** provision runtime secrets.
## 1) Create non-committed secret files
```bash
cp secrets/.env.secrets.example secrets/stack-secrets.env
chmod 600 secrets/stack-secrets.env
```
Create these Docker secret files (all ignored by git):
- `secrets/nextcloud_db_root_password.txt`
- `secrets/nextcloud_db_password.txt`
- `secrets/nextcloud_admin_password.txt`
- `secrets/nextcloud_smtp_password.txt`
- `secrets/nextcloud_redis_password.txt`
- `secrets/passbolt_db_password.txt`
- `secrets/gramps_db_password.txt`
- `secrets/influxdb_init_password.txt`
- `secrets/prometheus_kuma_basic_auth_password.txt`
Recommended permissions:
```bash
chmod 600 secrets/*.txt
```
## 2) Rotate previously committed credentials
These values were previously hardcoded and must be rotated in upstream systems immediately:
- Database credentials (Nextcloud, Passbolt, Gramps, InfluxDB).
- Nextcloud SMTP app password.
- Authelia reset JWT secret, session secret, storage encryption key.
- Traefik CrowdSec LAPI key.
- Gotify admin password.
- Prometheus Uptime Kuma basic-auth password.
## 3) Start stack
After secrets are provisioned:
```bash
docker compose -f core/docker-compose.yml up -d
docker compose -f monitoring/prometheus/docker-compose.yml up -d
docker compose -f apps/nextcloud/docker-compose.yml up -d
```
+31
View File
@@ -0,0 +1,31 @@
# Credential Inventory (apps/, core/, monitoring/)
## apps/
- `apps/nextcloud/docker-compose.yml`
- `MYSQL_PASSWORD` (nextcloud-webapp) -> `MYSQL_PASSWORD_FILE` + Docker secret.
- `SMTP_PASSWORD` -> `SMTP_PASSWORD_FILE` + Docker secret.
- `REDIS_HOST_PASSWORD` -> `REDIS_HOST_PASSWORD_FILE` + Docker secret.
- `MYSQL_ROOT_PASSWORD`, `MYSQL_PASSWORD`, `NEXTCLOUD_ADMIN_PASSWORD` (nextcloud-db) -> `_FILE` variants + Docker secrets.
- Redis `--requirepass` inline value -> read from Docker secret at runtime.
- `apps/passbolt/docker-compose.yml`
- `MYSQL_PASSWORD`, `DATASOURCES_DEFAULT_PASSWORD` -> `_FILE` variants + Docker secret.
- `apps/gramps/docker-compose.yml`
- `POSTGRES_PASSWORD` -> `POSTGRES_PASSWORD_FILE` + Docker secret.
- `DB_URI` password + `INITIAL_ADMIN_PASSWORD` -> env references from non-committed secrets env file.
## core/
- `core/authelia/configuration.yml`
- `identity_validation.reset_password.jwt_secret` -> `${AUTHELIA_JWT_SECRET}`.
- `session.secret` -> `${AUTHELIA_SESSION_SECRET}`.
- `storage.encryption_key` -> `${AUTHELIA_STORAGE_ENCRYPTION_KEY}`.
- `core/traefik/dynamic.yml`
- `crowdsecLapiKey` -> `${CROWDSEC_LAPI_KEY}`.
## monitoring/
- `monitoring/gotify/docker-compose.yml`
- `GOTIFY_DEFAULTUSER_PASS` -> `${GOTIFY_DEFAULTUSER_PASS}` from non-committed secrets env file.
- `monitoring/prometheus/docker-compose.yml`
- `DOCKER_INFLUXDB_INIT_PASSWORD` -> `DOCKER_INFLUXDB_INIT_PASSWORD_FILE` + Docker secret.
- `PIHOLE_PASSWORD` -> `${PIHOLE_PASSWORD}` from non-committed secrets env file.
- `monitoring/prometheus/prometheus.yml`
- Uptime Kuma basic_auth `password` -> `password_file` mounted from non-committed secret file.
+4 -4
View File
@@ -5,10 +5,10 @@ services:
image: gitea/gitea:latest # change to 1-rootless once find out how to move data. image: gitea/gitea:latest # change to 1-rootless once find out how to move data.
restart: always restart: always
environment: environment:
- USER_UID=1000 - USER_UID=${GITEA_USER_UID}
- USER_GID=1000 - USER_GID=${GITEA_USER_GID}
- GITEA__database__DB_TYPE=sqlite3 - GITEA__database__DB_TYPE=${GITEA_DB_TYPE}
- GITEA__server__ROOT_URL=https://gitea.lan.ddnsgeek.com/ - GITEA__server__ROOT_URL=${GITEA_ROOT_URL}
volumes: volumes:
- ${PROJECT_ROOT}/apps/gitea/data:/data - ${PROJECT_ROOT}/apps/gitea/data:/data
networks: networks:
+20 -18
View File
@@ -4,22 +4,25 @@ services:
image: postgres:13 image: postgres:13
container_name: gramps-db container_name: gramps-db
restart: always restart: always
env_file:
- ${SECRETS_ENV_FILE}
environment: environment:
POSTGRES_USER: gramps POSTGRES_USER: ${GRAMPS_DB_USER}
POSTGRES_PASSWORD: grampspassword POSTGRES_PASSWORD_FILE: /run/secrets/gramps_db_password
POSTGRES_DB: gramps POSTGRES_DB: ${GRAMPS_DB_NAME}
secrets:
- gramps_db_password
volumes: volumes:
- ${PROJECT_ROOT}/apps/gramps/db:/var/lib/postgresql - ${PROJECT_ROOT}/apps/gramps/db:/var/lib/postgresql
networks: networks:
- gramps - gramps
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -h db -p 5432 -U gramps -d gramps"] test: ["CMD-SHELL", "pg_isready -h gramps-db -p 5432 -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 12 retries: 12
start_period: 30s start_period: 30s
grampsweb: grampsweb:
profiles: ["apps","all","gramps"] profiles: ["apps","all","gramps"]
image: ghcr.io/gramps-project/grampsweb:latest image: ghcr.io/gramps-project/grampsweb:latest
@@ -27,17 +30,17 @@ services:
depends_on: depends_on:
- gramps-db - gramps-db
restart: always restart: always
# ports: env_file:
# - "5000:5000" # access via http://localhost:5000 - ${SECRETS_ENV_FILE}
environment: environment:
DB_URI: postgresql://gramps:grampspassword@db:5432/gramps DB_URI: ${GRAMPS_DB_URI}
GRAMPSWEB_LOGLEVEL: INFO GRAMPSWEB_LOGLEVEL: ${GRAMPSWEB_LOGLEVEL}
# default admin user created on first run: # default admin user created on first run:
INITIAL_ADMIN: admin INITIAL_ADMIN: ${GRAMPS_INITIAL_ADMIN}
INITIAL_ADMIN_PASSWORD: admin INITIAL_ADMIN_PASSWORD: ${GRAMPS_INITIAL_ADMIN_PASSWORD}
# optional: storage paths inside container # optional: storage paths inside container
GRAMPSWEB_MEDIAPATH: /app/media GRAMPSWEB_MEDIAPATH: ${GRAMPSWEB_MEDIAPATH}
GRAMPSWEB_TREE: "main" GRAMPSWEB_TREE: "${GRAMPSWEB_TREE}"
volumes: volumes:
- ${PROJECT_ROOT}/apps/gramps/data/users:/app/users - ${PROJECT_ROOT}/apps/gramps/data/users:/app/users
- ${PROJECT_ROOT}/apps/gramps/data/media:/app/media - ${PROJECT_ROOT}/apps/gramps/data/media:/app/media
@@ -62,10 +65,9 @@ services:
retries: 6 retries: 6
start_period: 60s start_period: 60s
networks: networks:
# traefik_reverse_proxy:
# external: true
gramps: gramps:
# driver: bridge
secrets:
gramps_db_password:
file: ${PROJECT_ROOT}/secrets/gramps_db_password.txt
+56 -44
View File
@@ -1,12 +1,13 @@
services: services:
nextcloud-webapp: nextcloud-webapp:
# image: nextcloud:production
profiles: ["apps","all","nextcloud"] profiles: ["apps","all","nextcloud"]
build: build:
context: ${PROJECT_ROOT}/apps/nextcloud context: ${PROJECT_ROOT}/apps/nextcloud
container_name: nextcloud-webapp container_name: nextcloud-webapp
restart: always restart: always
hostname: nextcloud.lan.ddnsgeek.com hostname: ${NEXTCLOUD_TRUSTED_DOMAINS}
# env_file:
# - ${SECRETS_ENV_FILE}
volumes: volumes:
- ${PROJECT_ROOT}/apps/nextcloud/data:/var/www/html/data:rw - ${PROJECT_ROOT}/apps/nextcloud/data:/var/www/html/data:rw
- ${PROJECT_ROOT}/apps/nextcloud/config:/var/www/html/config:rw - ${PROJECT_ROOT}/apps/nextcloud/config:/var/www/html/config:rw
@@ -16,31 +17,33 @@ services:
- nextcloud-db - nextcloud-db
- nextcloud-redis - nextcloud-redis
environment: environment:
- MYSQL_PASSWORD=R1m@dmin - MYSQL_PASSWORD_FILE=/run/secrets/nextcloud_db_password
- MYSQL_DATABASE=nextcloud - MYSQL_DATABASE=${NEXTCLOUD_MYSQL_DATABASE}
- MYSQL_USER=nextcloud - MYSQL_USER=${NEXTCLOUD_DB_USER}
- MYSQL_HOST=nextcloud_db:3306 - MYSQL_HOST=${NEXTCLOUD_MYSQL_HOST}
- NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.lan.ddnsgeek.com - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_TRUSTED_DOMAINS}
- OVERWRITEPROTOCOL=https - OVERWRITEPROTOCOL=${NEXTCLOUD_OVERWRITEPROTOCOL}
- OVERWRITECLIURL=https://nextcloud.lan.ddnsgeek.com - OVERWRITECLIURL=${NEXTCLOUD_OVERWRITECLIURL}
- SMTP_HOST=${NEXTCLOUD_SMTP_HOST}
- SMTP_HOST=smtp.gmail.com - SMTP_SECURE=${NEXTCLOUD_SMTP_SECURE}
- SMTP_SECURE=tls - SMTP_PORT=${NEXTCLOUD_SMTP_PORT}
- SMTP_PORT=587 - SMTP_AUTHTYPE=${NEXTCLOUD_SMTP_AUTHTYPE}
- SMTP_AUTHTYPE=login - MAIL_FROM_ADDRESS=${NEXTCLOUD_SMTP_FROM_ADDRESS}
- MAIL_FROM_ADDRESS=beatz174 - MAIL_DOMAIN=${NEXTCLOUD_SMTP_DOMAIN}
- MAIL_DOMAIN=gmail.com - SMTP_NAME=${NEXTCLOUD_SMTP_NAME}
- SMTP_NAME=beatz174@gmail.com - SMTP_PASSWORD_FILE=/run/secrets/nextcloud_smtp_password
- SMTP_PASSWORD=kqdw fvml wlag ldgv - REDIS_HOST=${NEXTCLOUD_REDIS_HOST}
- REDIS_HOST_PORT=${NEXTCLOUD_REDIS_HOST_PORT}
- REDIS_HOST=redis - REDIS_HOST_PASSWORD_FILE=/run/secrets/nextcloud_redis_password
- REDIS_HOST_PORT=6379 secrets:
- REDIS_HOST_PASSWORD=TzBF8wcJNmVd9p2CTmBejPS9dpye6kWQeH3DmrQS9TPfTRriSHFN5VqH4CgzcuVZYWH2GBb7QU5GuEpNDGYdKjM6hjmLyjSgCFMiPms3Hv9n - nextcloud_db_password
- nextcloud_smtp_password
- nextcloud_redis_password
networks: networks:
- traefik - traefik
- nextcloud - nextcloud
labels: labels:
- "traefik.http.routers.nextcloud.rule=Host(`nextcloud.lan.ddnsgeek.com`)" - "traefik.http.routers.nextcloud.rule=Host(`${NEXTCLOUD_TRUSTED_DOMAINS}`)"
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.http.routers.nextcloud.entrypoints=websecure" - "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls.certresolver=myresolver" - "traefik.http.routers.nextcloud.tls.certresolver=myresolver"
@@ -54,7 +57,6 @@ services:
- "traefik.http.middlewares.nextcloud-webfinger.redirectregex.regex=https://(.*)/.well-known/webfinger" - "traefik.http.middlewares.nextcloud-webfinger.redirectregex.regex=https://(.*)/.well-known/webfinger"
- "traefik.http.middlewares.nextcloud-webfinger.redirectregex.replacement=https://$${1}/nextcloud/index.php/.well-known/webfinger" - "traefik.http.middlewares.nextcloud-webfinger.redirectregex.replacement=https://$${1}/nextcloud/index.php/.well-known/webfinger"
- "traefik.docker.network=core_traefik" - "traefik.docker.network=core_traefik"
healthcheck: healthcheck:
test: test:
- CMD-SHELL - CMD-SHELL
@@ -68,9 +70,6 @@ services:
retries: 6 retries: 6
start_period: 180s start_period: 180s
nextcloud-db: nextcloud-db:
image: mariadb:11.4 image: mariadb:11.4
restart: always restart: always
@@ -78,36 +77,41 @@ services:
container_name: nextcloud-db container_name: nextcloud-db
hostname: nextcloud_db hostname: nextcloud_db
command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
volumes: volumes:
- ${PROJECT_ROOT}/apps/nextcloud/database:/var/lib/mysql:rw - ${PROJECT_ROOT}/apps/nextcloud/database:/var/lib/mysql:rw
environment: environment:
- MYSQL_ROOT_PASSWORD=R1m@dmin - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/nextcloud_db_root_password
- MYSQL_PASSWORD=R1m@dmin - MYSQL_PASSWORD_FILE=/run/secrets/nextcloud_db_password
- MYSQL_DATABASE=nextcloud - MYSQL_DATABASE=${NEXTCLOUD_MYSQL_DATABASE}
- MYSQL_USER=nextcloud - MYSQL_USER=${NEXTCLOUD_DB_USER}
- MARIADB_AUTO_UPGRADE=1 - MARIADB_AUTO_UPGRADE=${NEXTCLOUD_MARIADB_AUTO_UPGRADE}
- NEXTCLOUD_ADMIN_USER=admin - NEXTCLOUD_ADMIN_USER=${NEXTCLOUD_ADMIN_USER}
- NEXTCLOUD_ADMIN_PASSWORD=R1m@dmin - NEXTCLOUD_ADMIN_PASSWORD_FILE=/run/secrets/nextcloud_admin_password
secrets:
- nextcloud_db_root_password
- nextcloud_db_password
- nextcloud_admin_password
networks: networks:
- nextcloud - nextcloud
labels: labels:
- "io.portainer.accesscontrol.public" - "io.portainer.accesscontrol.public"
healthcheck: healthcheck:
test: ["CMD-SHELL", "mariadb-admin ping -u nextcloud --password=R1m@dmin --silent"] test: ["CMD-SHELL", "mariadb-admin ping -u $$MYSQL_USER --password=$$(cat /run/secrets/nextcloud_db_password) --silent"]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 12 retries: 12
start_period: 60s start_period: 60s
nextcloud-redis: nextcloud-redis:
image: "redis" image: "redis"
profiles: ["apps","all","nextcloud"] profiles: ["apps","all","nextcloud"]
command: ["redis-server", "--requirepass", "TzBF8wcJNmVd9p2CTmBejPS9dpye6kWQeH3DmrQS9TPfTRriSHFN5VqH4CgzcuVZYWH2GBb7QU5GuEpNDGYdKjM6hjmLyjSgCFMiPms3Hv9n", "--appendonly", "yes", "--save", "60", "1000"] command: ["sh", "-c", "redis-server --requirepass \"$$(cat /run/secrets/nextcloud_redis_password)\" --appendonly yes --save 60 1000"]
hostname: redis hostname: redis
container_name: nextcloud-redis container_name: nextcloud-redis
environment: secrets:
- REDIS_HOST_PASSWORD=TzBF8wcJNmVd9p2CTmBejPS9dpye6kWQeH3DmrQS9TPfTRriSHFN5VqH4CgzcuVZYWH2GBb7QU5GuEpNDGYdKjM6hjmLyjSgCFMiPms3Hv9n - nextcloud_redis_password
volumes: volumes:
- ${PROJECT_ROOT}/apps/nextcloud/data/redis:/data:rw - ${PROJECT_ROOT}/apps/nextcloud/data/redis:/data:rw
restart: always restart: always
@@ -116,15 +120,23 @@ services:
labels: labels:
- "io.portainer.accesscontrol.public" - "io.portainer.accesscontrol.public"
healthcheck: healthcheck:
test: ["CMD-SHELL", "redis-cli -a TzBF8wcJNmVd9p2CTmBejPS9dpye6kWQeH3DmrQS9TPfTRriSHFN5VqH4CgzcuVZYWH2GBb7QU5GuEpNDGYdKjM6hjmLyjSgCFMiPms3Hv9n PING | grep -q PONG"] test: ["CMD-SHELL", "redis-cli -a \"$$(cat /run/secrets/nextcloud_redis_password)\" PING | grep -q PONG"]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 6 retries: 6
start_period: 10s start_period: 10s
networks: networks:
# traefik_reverse_proxy:
# external: true
nextcloud: nextcloud:
# driver: bridge
secrets:
nextcloud_db_root_password:
file: ${PROJECT_ROOT}/secrets/nextcloud_db_root_password.txt
nextcloud_db_password:
file: ${PROJECT_ROOT}/secrets/nextcloud_db_password.txt
nextcloud_admin_password:
file: ${PROJECT_ROOT}/secrets/nextcloud_admin_password.txt
nextcloud_smtp_password:
file: ${PROJECT_ROOT}/secrets/nextcloud_smtp_password.txt
nextcloud_redis_password:
file: ${PROJECT_ROOT}/secrets/nextcloud_redis_password.txt
+23 -21
View File
@@ -4,17 +4,21 @@ services:
container_name: passbolt-db container_name: passbolt-db
image: mariadb:12 image: mariadb:12
restart: always restart: always
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
environment: environment:
MYSQL_RANDOM_ROOT_PASSWORD: "true" MYSQL_RANDOM_ROOT_PASSWORD: ${PASSBOLT_MYSQL_RANDOM_ROOT_PASSWORD}
MYSQL_DATABASE: "passbolt" MYSQL_DATABASE: ${PASSBOLT_DB_NAME}
MYSQL_USER: "passbolt" MYSQL_USER: ${PASSBOLT_DB_USER}
MYSQL_PASSWORD: "P4ssb0lt" MYSQL_PASSWORD_FILE: /run/secrets/passbolt_db_password
secrets:
- passbolt_db_password
volumes: volumes:
- ${PROJECT_ROOT}/apps/passbolt/data/database:/var/lib/mysql - ${PROJECT_ROOT}/apps/passbolt/data/database:/var/lib/mysql
networks: networks:
- passbolt - passbolt
healthcheck: healthcheck:
test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u\"$$MARIADB_USER\" -p\"$$MARIADB_PASSWORD\" --silent"] test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u\"$$MYSQL_USER\" -p\"$$(cat /run/secrets/passbolt_db_password)\" --silent"]
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 12 retries: 12
@@ -22,22 +26,24 @@ services:
labels: labels:
- "io.portainer.accesscontrol.public" - "io.portainer.accesscontrol.public"
passbolt-webapp: passbolt-webapp:
image: passbolt/passbolt:latest-ce image: passbolt/passbolt:latest-ce
profiles: ["apps","all","passbolt"] profiles: ["apps","all","passbolt"]
container_name: passbolt-webapp container_name: passbolt-webapp
#Alternatively you can use rootless:
restart: always restart: always
depends_on: depends_on:
- passbolt-db - passbolt-db
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
environment: environment:
APP_FULL_BASE_URL: https://passbolt.lan.ddnsgeek.com APP_FULL_BASE_URL: ${PASSBOLT_APP_FULL_BASE_URL}
DATASOURCES_DEFAULT_HOST: "passbolt-db" DATASOURCES_DEFAULT_HOST: ${PASSBOLT_DATASOURCES_DEFAULT_HOST}
DATASOURCES_DEFAULT_USERNAME: "passbolt" DATASOURCES_DEFAULT_USERNAME: ${PASSBOLT_DB_USER}
DATASOURCES_DEFAULT_PASSWORD: "P4ssb0lt" DATASOURCES_DEFAULT_PASSWORD_FILE: /run/secrets/passbolt_db_password
DATASOURCES_DEFAULT_DATABASE: "passbolt" DATASOURCES_DEFAULT_DATABASE: ${PASSBOLT_DB_NAME}
PASSBOLT_GPG_SERVER_KEY_FINGERPRINT: "CBBB2B8F3E9FACA114537ACB8965B750F7363586" PASSBOLT_GPG_SERVER_KEY_FINGERPRINT: ${PASSBOLT_GPG_SERVER_KEY_FINGERPRINT}
secrets:
- passbolt_db_password
volumes: volumes:
- ${PROJECT_ROOT}/apps/passbolt/data/gpg:/etc/passbolt/gpg - ${PROJECT_ROOT}/apps/passbolt/data/gpg:/etc/passbolt/gpg
- ${PROJECT_ROOT}/apps/passbolt/data/jwt:/etc/passbolt/jwt - ${PROJECT_ROOT}/apps/passbolt/data/jwt:/etc/passbolt/jwt
@@ -60,20 +66,16 @@ services:
- "traefik.http.routers.passbolt.tls.certresolver=myresolver" - "traefik.http.routers.passbolt.tls.certresolver=myresolver"
- "io.portainer.accesscontrol.public" - "io.portainer.accesscontrol.public"
- "traefik.docker.network=core_traefik" - "traefik.docker.network=core_traefik"
healthcheck: healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost/healthcheck/status | grep -qx OK"] test: ["CMD-SHELL", "curl -fsS http://localhost/healthcheck/status | grep -qx OK"]
# su -s /bin/sh -c "/usr/share/php/passbolt/bin/cake passbolt healthcheck" www-data
# | grep -q "No error found"
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 6 retries: 6
start_period: 120s start_period: 120s
networks: networks:
# traefik_reverse_proxy:
# external: true
# internal:
# driver: bridge
passbolt: passbolt:
secrets:
passbolt_db_password:
file: ${PROJECT_ROOT}/secrets/passbolt_db_password.txt
+7 -3
View File
@@ -23,8 +23,6 @@ authentication_backend:
access_control: access_control:
default_policy: deny default_policy: deny
rules: rules:
# - domain: "*.lan.ddnsgeek.com"
# policy: two_factor
- domain: alertmanager.lan.ddnsgeek.com - domain: alertmanager.lan.ddnsgeek.com
resources: resources:
- "^/api/.*" - "^/api/.*"
@@ -35,6 +33,13 @@ access_control:
- "^/health" - "^/health"
policy: bypass policy: bypass
- domain: node-red.lan.ddnsgeek.com
resources:
- "^/health"
- "^/uptime-kuma"
- "^/docker-update-lockouts/clear"
policy: bypass
- domain: prometheus.lan.ddnsgeek.com - domain: prometheus.lan.ddnsgeek.com
resources: resources:
- "^/-/healthy" - "^/-/healthy"
@@ -45,7 +50,6 @@ access_control:
- "^/metrics" - "^/metrics"
policy: bypass policy: bypass
- domain: "*.lan.ddnsgeek.com" - domain: "*.lan.ddnsgeek.com"
policy: two_factor policy: two_factor
+10 -1
View File
@@ -17,6 +17,8 @@ services:
build: build:
context: ${PROJECT_ROOT}/core context: ${PROJECT_ROOT}/core
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
@@ -52,6 +54,7 @@ services:
restart: always restart: always
environment: environment:
- COLLECTIONS=crowdsecurity/traefik - COLLECTIONS=crowdsecurity/traefik
# - CROWDSEC_LAPI_KEY=${CROWDSEC_LAPI_KEY}
volumes: volumes:
- ${PROJECT_ROOT}/core/crowdsec/logs:/logs:ro - ${PROJECT_ROOT}/core/crowdsec/logs:/logs:ro
- ${PROJECT_ROOT}/core/crowdsec/data:/var/lib/crowdsec/data - ${PROJECT_ROOT}/core/crowdsec/data:/var/lib/crowdsec/data
@@ -73,7 +76,7 @@ services:
container_name: error-pages container_name: error-pages
read_only: true read_only: true
environment: environment:
TEMPLATE_NAME: app-down TEMPLATE_NAME: ${ERROR_PAGES_TEMPLATE_NAME}
networks: networks:
# - reverse_proxy # - reverse_proxy
- traefik - traefik
@@ -99,6 +102,12 @@ services:
restart: always restart: always
build: build:
context: ${PROJECT_ROOT}/core/authelia context: ${PROJECT_ROOT}/core/authelia
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
# environment:
# - AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET:${AUTHELIA_JWT_SECRET}
# - AUTHELIA_SESSION_SECRET:${AUTHELIA_SESSION_SECRET}
# - AUTHELIA_STORAGE_ENCRYPTION_KEY:${AUTHELIA_STORAGE_ENCRYPTION_KEY}
volumes: volumes:
- ${PROJECT_ROOT}/core/authelia:/config - ${PROJECT_ROOT}/core/authelia:/config
networks: networks:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
update-test: update-test:
image: nginx:1.27.4 image: nginx:1.28.1
container_name: update-test container_name: update-test
profiles: ["test"] profiles: ["test"]
healthcheck: healthcheck:
+1 -1
View File
@@ -4,7 +4,7 @@ http:
plugin: plugin:
crowdsec-bouncer: crowdsec-bouncer:
crowdsecMode: live crowdsecMode: live
crowdsecLapiKey: HeneLa2mazFVzl5+DQRKOdchBuJxKdjrHsHBE/03Acs crowdsecLapiKey: ${CROWDSEC_LAPI_KEY}
crowdsecLapiHost: crowdsec:8080 crowdsecLapiHost: crowdsec:8080
crowdsecLapiScheme: http crowdsecLapiScheme: http
+56
View File
@@ -2,3 +2,59 @@ PROJECT_ROOT=/home/nixos/docker
DOMAIN=lan.ddnsgeek.com DOMAIN=lan.ddnsgeek.com
TZ=Australia/Brisbane TZ=Australia/Brisbane
EMAIL=wayne.bennett@live.com EMAIL=wayne.bennett@live.com
SECRETS_ENV_FILE=${PROJECT_ROOT}/secrets/stack-secrets.env
# Core
CROWDSEC_COLLECTIONS=crowdsecurity/traefik
ERROR_PAGES_TEMPLATE_NAME=app-down
# Gitea
GITEA_USER_UID=1000
GITEA_USER_GID=1000
GITEA_DB_TYPE=sqlite3
GITEA_ROOT_URL=https://gitea.lan.ddnsgeek.com/
# Grafana
GRAFANA_ROOT_URL=https://grafana.lan.ddnsgeek.com/
# Nextcloud
NEXTCLOUD_MYSQL_DATABASE=nextcloud
NEXTCLOUD_MYSQL_HOST=nextcloud_db:3306
NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.lan.ddnsgeek.com
NEXTCLOUD_OVERWRITEPROTOCOL=https
NEXTCLOUD_OVERWRITECLIURL=https://${NEXTCLOUD_TRUSTED_DOMAINS}
NEXTCLOUD_SMTP_HOST=smtp.gmail.com
NEXTCLOUD_SMTP_SECURE=tls
NEXTCLOUD_SMTP_PORT=587
NEXTCLOUD_SMTP_AUTHTYPE=login
NEXTCLOUD_REDIS_HOST=redis
NEXTCLOUD_REDIS_HOST_PORT=6379
NEXTCLOUD_MARIADB_AUTO_UPGRADE=1
# Passbolt
PASSBOLT_MYSQL_RANDOM_ROOT_PASSWORD=true
PASSBOLT_MYSQL_DATABASE=passbolt
PASSBOLT_MYSQL_USER=passbolt
PASSBOLT_APP_FULL_BASE_URL=https://passbolt.lan.ddnsgeek.com
PASSBOLT_DATASOURCES_DEFAULT_HOST=passbolt-db
# Gramps
GRAMPSWEB_LOGLEVEL=INFO
GRAMPSWEB_MEDIAPATH=/app/media
GRAMPSWEB_TREE=main
# Prometheus stack
INFLUXDB_INIT_MODE=setup
INFLUXDB_INIT_ORG=pbs
INFLUXDB_INIT_BUCKET=telemetry
DOCKER_EXPORTER_LOG_LEVEL=INFO
PIHOLE_HOSTNAME=pihole.sweet.home
PIHOLE_EXPORTER_PORT=9617
# Gotify
GOTIFY_REGISTRATION=false
# Portainer
PORTAINER_GODEBUG=netdns=cgo
+5 -11
View File
@@ -4,20 +4,18 @@ services:
image: gotify/server:latest image: gotify/server:latest
container_name: gotify container_name: gotify
restart: always restart: always
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
volumes: volumes:
- ${PROJECT_ROOT}/monitoring/gotify/data:/app/data - ${PROJECT_ROOT}/monitoring/gotify/data:/app/data
environment: environment:
- TZ=${TZ} - TZ=${TZ}
- GOTIFY_DEFAULTUSER_NAME=admin - GOTIFY_DEFAULTUSER_NAME=${GOTIFY_DEFAULTUSER_NAME}
- GOTIFY_DEFAULTUSER_PASS=R1m@dmin - GOTIFY_DEFAULTUSER_PASS=${GOTIFY_DEFAULTUSER_PASS}
- GOTIFY_REGISTRATION=false - GOTIFY_REGISTRATION=${GOTIFY_REGISTRATION}
networks: networks:
# - traefik_reverse_proxy
- traefik - traefik
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
- "traefik.docker.network=core_traefik" - "traefik.docker.network=core_traefik"
@@ -26,7 +24,3 @@ services:
- "traefik.http.routers.gotify.entrypoints=websecure" - "traefik.http.routers.gotify.entrypoints=websecure"
- "traefik.http.routers.gotify.tls.certresolver=myresolver" - "traefik.http.routers.gotify.tls.certresolver=myresolver"
- "traefik.http.services.gotify.loadbalancer.server.port=80" - "traefik.http.services.gotify.loadbalancer.server.port=80"
#networks:
# traefik_reverse_proxy:
# external: true
+1 -1
View File
@@ -5,7 +5,7 @@ services:
container_name: grafana container_name: grafana
restart: unless-stopped restart: unless-stopped
environment: environment:
- GF_SERVER_ROOT_URL=https://grafana.lan.ddnsgeek.com/ - GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL}
volumes: volumes:
- ${PROJECT_ROOT}/monitoring/grafana/data:/var/lib/grafana - ${PROJECT_ROOT}/monitoring/grafana/data:/var/lib/grafana
networks: networks:
+1
View File
@@ -3,4 +3,5 @@ FROM nodered/node-red:latest
USER root USER root
RUN apk add --no-cache docker-cli docker-cli-compose RUN apk add --no-cache docker-cli docker-cli-compose
RUN addgroup -g 131 -S docker && addgroup node-red docker RUN addgroup -g 131 -S docker && addgroup node-red docker
USER node-red USER node-red
+4 -1
View File
@@ -14,11 +14,14 @@ services:
- ALL - ALL
security_opt: security_opt:
- no-new-privileges:true - no-new-privileges:true
environment:
- TZ=${TZ}
# ports: # ports:
# - "1880:1880" # - "1880:1880"
volumes: volumes:
- ${PROJECT_ROOT}/monitoring/node-red/data:/data - ${PROJECT_ROOT}/monitoring/node-red/data:/data
- ${PROJECT_ROOT}:/compose - ${PROJECT_ROOT}:/compose/docker:ro
- /home/nixos/raspi:/compose/raspi:ro
- ${PROJECT_ROOT}/default-environment.env:/usr/src/node-red/default-environment.env:ro - ${PROJECT_ROOT}/default-environment.env:/usr/src/node-red/default-environment.env:ro
- ${PROJECT_ROOT}/default-network.yml:/usr/src/node-red/default-network.yml:ro - ${PROJECT_ROOT}/default-network.yml:/usr/src/node-red/default-network.yml:ro
- ${PROJECT_ROOT}/core/docker-compose.yml:/usr/src/node-red/core/docker-compose.yml:ro - ${PROJECT_ROOT}/core/docker-compose.yml:/usr/src/node-red/core/docker-compose.yml:ro
+1 -1
View File
@@ -24,7 +24,7 @@ services:
- traefik.http.services.portainer.loadbalancer.server.port=9000 - traefik.http.services.portainer.loadbalancer.server.port=9000
environment: environment:
- GODEBUG=netdns=cgo - GODEBUG=${PORTAINER_GODEBUG}
# healthcheck: # healthcheck:
# test: ["CMD", "wget", "--spider", "-q", "https://portainer.lan.ddnsgeek.com/api/status"] # test: ["CMD", "wget", "--spider", "-q", "https://portainer.lan.ddnsgeek.com/api/status"]
# interval: 30s # interval: 30s
+43 -28
View File
@@ -31,6 +31,8 @@ services:
prometheus: prometheus:
profiles: ["monitoring","all","prometheus"] profiles: ["monitoring","all","prometheus"]
image: prom/prometheus:latest image: prom/prometheus:latest
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
container_name: prometheus container_name: prometheus
depends_on: depends_on:
# - alertmanager # - alertmanager
@@ -49,6 +51,7 @@ services:
- ${PROJECT_ROOT}/monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro - ${PROJECT_ROOT}/monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ${PROJECT_ROOT}/monitoring/prometheus/data:/prometheus - ${PROJECT_ROOT}/monitoring/prometheus/data:/prometheus
- ${PROJECT_ROOT}/monitoring/prometheus/rules:/etc/prometheus/rules:ro - ${PROJECT_ROOT}/monitoring/prometheus/rules:/etc/prometheus/rules:ro
- ${PROJECT_ROOT}/secrets/prometheus_kuma_basic_auth_password.txt:/run/secrets/prometheus_kuma_basic_auth_password:ro
restart: unless-stopped restart: unless-stopped
labels: labels:
@@ -80,7 +83,7 @@ services:
# volumes: # volumes:
# - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro # - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
# restart: unless-stopped # restart: unless-stopped
# networks: # secrets:
# - edge # - edge
# - traefik_reverse_proxy # - traefik_reverse_proxy
# healthcheck: # healthcheck:
@@ -128,14 +131,18 @@ services:
image: influxdb:2.7 image: influxdb:2.7
container_name: influxdb container_name: influxdb
restart: unless-stopped restart: unless-stopped
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
volumes: volumes:
- ${PROJECT_ROOT}/monitoring/influxdb:/var/lib/influxdb2 - ${PROJECT_ROOT}/monitoring/influxdb:/var/lib/influxdb2
environment: environment:
DOCKER_INFLUXDB_INIT_MODE: setup DOCKER_INFLUXDB_INIT_MODE: ${INFLUXDB_INIT_MODE}
DOCKER_INFLUXDB_INIT_USERNAME: admin DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUXDB_INIT_USERNAME}
DOCKER_INFLUXDB_INIT_PASSWORD: adminpassword DOCKER_INFLUXDB_INIT_PASSWORD_FILE: /run/secrets/influxdb_init_password
DOCKER_INFLUXDB_INIT_ORG: pbs DOCKER_INFLUXDB_INIT_ORG: ${INFLUXDB_INIT_ORG}
DOCKER_INFLUXDB_INIT_BUCKET: telemetry DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUXDB_INIT_BUCKET}
secrets:
- influxdb_init_password
networks: networks:
# - edge # - edge
# - traefik_reverse_proxy # - traefik_reverse_proxy
@@ -199,24 +206,24 @@ services:
volumes: volumes:
- ~/.docker/config.json:/root/.docker/config.json:ro - ~/.docker/config.json:/root/.docker/config.json:ro
- ${PROJECT_ROOT}/monitoring/docker-exporter/data:/data:rw - ${PROJECT_ROOT}/monitoring/docker-exporter/data:/data:rw
- ${PROJECT_ROOT}:/compose - ${PROJECT_ROOT}:/compose:ro
- ${PROJECT_ROOT}/default-environment.env:/compose/default-environment.env:ro # - ${PROJECT_ROOT}/default-environment.env:/compose/default-environment.env:ro
- ${PROJECT_ROOT}/default-network.yml:/compose/default-network.yml:ro # - ${PROJECT_ROOT}/default-network.yml:/compose/default-network.yml:ro
- ${PROJECT_ROOT}/core/docker-compose.yml:/compose/core/docker-compose.yml:ro # - ${PROJECT_ROOT}/core/docker-compose.yml:/compose/core/docker-compose.yml:ro
- ${PROJECT_ROOT}/monitoring/prometheus/docker-compose.yml:/compose/monitoring/prometheus/docker-compose.yml:ro # - ${PROJECT_ROOT}/monitoring/prometheus/docker-compose.yml:/compose/monitoring/prometheus/docker-compose.yml:ro
- ${PROJECT_ROOT}/monitoring/gotify/docker-compose.yml:/compose/monitoring/gotify/docker-compose.yml:ro # - ${PROJECT_ROOT}/monitoring/gotify/docker-compose.yml:/compose/monitoring/gotify/docker-compose.yml:ro
- ${PROJECT_ROOT}/monitoring/grafana/docker-compose.yml:/compose/monitoring/grafana/docker-compose.yml:ro # - ${PROJECT_ROOT}/monitoring/grafana/docker-compose.yml:/compose/monitoring/grafana/docker-compose.yml:ro
- ${PROJECT_ROOT}/monitoring/portainer/docker-compose.yml:/compose/monitoring/portainer/docker-compose.yml:ro # - ${PROJECT_ROOT}/monitoring/portainer/docker-compose.yml:/compose/monitoring/portainer/docker-compose.yml:ro
- ${PROJECT_ROOT}/monitoring/uptime-kuma/docker-compose.yml:/compose/monitoring/uptime-kuma/docker-compose.yml:> # - ${PROJECT_ROOT}/monitoring/uptime-kuma/docker-compose.yml:/compose/monitoring/uptime-kuma/docker-compose.yml:>
- ${PROJECT_ROOT}/apps/gitea/docker-compose.yml:/compose/apps/gitea/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/gitea/docker-compose.yml:/compose/apps/gitea/docker-compose.yml:ro
- ${PROJECT_ROOT}/apps/gramps/docker-compose.yml:/compose/apps/gramps/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/gramps/docker-compose.yml:/compose/apps/gramps/docker-compose.yml:ro
- ${PROJECT_ROOT}/apps/nextcloud/docker-compose.yml:/compose/apps/nextcloud/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/nextcloud/docker-compose.yml:/compose/apps/nextcloud/docker-compose.yml:ro
- ${PROJECT_ROOT}/apps/passbolt/docker-compose.yml:/compose/apps/passbolt/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/passbolt/docker-compose.yml:/compose/apps/passbolt/docker-compose.yml:ro
- ${PROJECT_ROOT}/apps/searxng/docker-compose.yml:/compose/apps/searxng/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/searxng/docker-compose.yml:/compose/apps/searxng/docker-compose.yml:ro
- ${PROJECT_ROOT}/apps/shift-recorder/docker-compose.yml:/compose/apps/shift-recorder/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/shift-recorder/docker-compose.yml:/compose/apps/shift-recorder/docker-compose.yml:ro
- ${PROJECT_ROOT}/apps/stockfill/docker-compose.yml:/compose/apps/stockfill/docker-compose.yml:ro # - ${PROJECT_ROOT}/apps/stockfill/docker-compose.yml:/compose/apps/stockfill/docker-compose.yml:ro
- ${PROJECT_ROOT}/monitoring/node-red/docker-compose.yml:/compose/monitoring/node-red/docker-compose.yml:ro # - ${PROJECT_ROOT}/monitoring/node-red/docker-compose.yml:/compose/monitoring/node-red/docker-compose.yml:ro
- ${PROJECT_ROOT}/core/test/docker-compose.yml:/compose/core/test/docker-compose.yml:ro # - ${PROJECT_ROOT}/core/test/docker-compose.yml:/compose/core/test/docker-compose.yml:ro
# ports: # ports:
@@ -240,12 +247,14 @@ services:
profiles: ["monitoring","all","prometheus-exporters"] profiles: ["monitoring","all","prometheus-exporters"]
image: ekofr/pihole-exporter:latest image: ekofr/pihole-exporter:latest
container_name: pihole-exporter container_name: pihole-exporter
# env_file:
# - ${PROJECT_ROOT}/secrets/stack-secrets.env
environment: environment:
PIHOLE_HOSTNAME: pihole.sweet.home PIHOLE_HOSTNAME: ${PIHOLE_HOSTNAME}
PIHOLE_PASSWORD: "" PIHOLE_PASSWORD: ${PIHOLE_PASSWORD}
PORT: 9617 PORT: ${PIHOLE_EXPORTER_PORT}
ports: ports:
- "9617:9617" - "${PIHOLE_EXPORTER_PORT}:${PIHOLE_EXPORTER_PORT}"
restart: unless-stopped restart: unless-stopped
networks: networks:
# - edge # - edge
@@ -262,3 +271,9 @@ services:
# traefik_reverse_proxy: # traefik_reverse_proxy:
# external: true # external: true
secrets:
influxdb_init_password:
file: ${PROJECT_ROOT}/secrets/influxdb_init_password.txt
+3 -2
View File
@@ -63,6 +63,7 @@ scrape_configs:
static_configs: static_configs:
- targets: - targets:
- telegraf:9273 - telegraf:9273
- raspberrypi.tail13f623.ts.net:9273
labels: labels:
role: docker role: docker
@@ -96,8 +97,8 @@ scrape_configs:
basic_auth: basic_auth:
username: wayne.bennett@live.com username: wayne.bennett@live.com
password: '4vjCco?[%{=+,t`):C' password_file: /run/secrets/prometheus_kuma_basic_auth_password
# password: '4vjCco?[%{=+,t`):C'
static_configs: static_configs:
- targets: - targets:
- monitor-kuma:3001 - monitor-kuma:3001
+35
View File
@@ -0,0 +1,35 @@
# Copy to secrets/stack-secrets.env and set real values.
# Do NOT commit secrets/stack-secrets.env.
NEXTCLOUD_DB_NAME=nextcloud
NEXTCLOUD_DB_USER=nextcloud
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_SMTP_FROM_ADDRESS=mailuser
NEXTCLOUD_SMTP_DOMAIN=example.com
NEXTCLOUD_SMTP_NAME=mailuser@example.com
PASSBOLT_DB_NAME=passbolt
PASSBOLT_DB_USER=passbolt
GRAMPS_DB_NAME=gramps
GRAMPS_DB_USER=gramps
GRAMPS_DB_PASSWORD=CHANGE_ME
GRAMPS_INITIAL_ADMIN=admin
GRAMPS_INITIAL_ADMIN_PASSWORD=CHANGE_ME
GOTIFY_DEFAULTUSER_NAME=admin
GOTIFY_DEFAULTUSER_PASS=CHANGE_ME
INFLUXDB_INIT_USERNAME=admin
INFLUXDB_INIT_ORG=homelab
INFLUXDB_INIT_BUCKET=telemetry
PIHOLE_HOSTNAME=pihole.example.com
PIHOLE_PASSWORD=CHANGE_ME
PROMETHEUS_KUMA_BASIC_AUTH_USERNAME=monitoring@example.com
AUTHELIA_JWT_SECRET=CHANGE_ME
AUTHELIA_SESSION_SECRET=CHANGE_ME
AUTHELIA_STORAGE_ENCRYPTION_KEY=CHANGE_ME
CROWDSEC_LAPI_KEY=CHANGE_ME
+2 -1
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
ENV="default-environment.env" ENV="default-environment.env"
SECRETS="secrets/stack-secrets.env"
PROJECT="core" PROJECT="core"
FILES=( FILES=(
-f default-network.yml -f default-network.yml
@@ -21,4 +22,4 @@ FILES=(
-f core/test/docker-compose.yml -f core/test/docker-compose.yml
) )
docker compose -p $PROJECT --env-file $ENV "${FILES[@]}" $1 $2 $3 $4 $5 $6 $7 $8 $9 docker compose -p $PROJECT --env-file $ENV --env-file $SECRETS "${FILES[@]}" $1 $2 $3 $4 $5 $6 $7 $8 $9
+13 -13
View File
@@ -1,13 +1,13 @@
07:29:20 INFO: === Update started: 2026-04-01 07:29:20 === 12:23:36 INFO: === Update started: 2026-04-04 12:23:36 ===
07:29:20 WARNING: Skipping traefik (directory does not exist) 12:23:36 WARNING: Skipping traefik (directory does not exist)
07:29:20 WARNING: Skipping nextcloud (directory does not exist) 12:23:36 WARNING: Skipping nextcloud (directory does not exist)
07:29:20 WARNING: Skipping passbolt (directory does not exist) 12:23:36 WARNING: Skipping passbolt (directory does not exist)
07:29:20 WARNING: Skipping searxng (directory does not exist) 12:23:36 WARNING: Skipping searxng (directory does not exist)
07:29:20 WARNING: Skipping gitea (directory does not exist) 12:23:36 WARNING: Skipping gitea (directory does not exist)
07:29:20 WARNING: Skipping gotify (directory does not exist) 12:23:36 WARNING: Skipping gotify (directory does not exist)
07:29:20 WARNING: Skipping grafana (directory does not exist) 12:23:36 WARNING: Skipping grafana (directory does not exist)
07:29:20 WARNING: Skipping gramps (directory does not exist) 12:23:36 WARNING: Skipping gramps (directory does not exist)
07:29:20 WARNING: Skipping portainer (directory does not exist) 12:23:36 WARNING: Skipping portainer (directory does not exist)
07:29:20 WARNING: Skipping prometheus (directory does not exist) 12:23:36 WARNING: Skipping prometheus (directory does not exist)
07:29:20 WARNING: Skipping uptime-kuma (directory does not exist) 12:23:36 WARNING: Skipping uptime-kuma (directory does not exist)
07:29:20 INFO: Pruning unused containers, images, networks, and volumes... 12:23:36 INFO: Pruning unused containers, images, networks, and volumes...