docker info

This commit is contained in:
root
2025-12-06 09:47:55 -08:00
parent 38d167ef21
commit 0f08fcb176
7 changed files with 1459 additions and 0 deletions

134
caddy/Caddyfile Normal file
View File

@@ -0,0 +1,134 @@
{
storage redis {
address caddy-redis:6379
}
#acme_ca https://acme.zerossl.com/v2/DV90
email charles.a.monroe@gmail.com
acme_dns cloudflare {env.CF_API_KEY}
}
# This reusable snippet contains the forward_auth configuration.
(authelia) {
forward_auth http://authelia:9091 {
uri /api/verify?rd=https://auth.poppyglen.cc/
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
}
auth.poppyglen.cc {
reverse_proxy http://authelia:9091 {
trusted_proxies 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 104.16.0.0/12 108.162.192.0/18 131.0.72.0/22 141.101.64.0/18 162.158.0.0/15 172.64.0.0/13 173.245.48.0/20 188.114.96.0/20 190.93.240.0/20 197.234.240.0/22 198.41.128.0/17 2400:cb00::/32 2405:8100::/32 2405:b500::/32 2606:4700::/32 2803:f800::/32 2a06:98c0::/29 2c0f:f248::/32
}
}
cloud.poppyglen.cc {
request_body {
max_size 10G
}
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains;"
Referrer-Policy no-referrer
X-Content-Type-Options nosniff
X-Download-Options noopen
X-Frame-Options SAMEORIGIN
X-Permitted-Cross-Domain-Policies none
X-Robots-Tag "noindex,nofollow"
X-XSS-Protection "1; mode=block"
Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"
}
log {
output file /data/caddy_access.log
format json
}
route {
import authelia
coraza_waf /etc/caddy/waf/nextcloud-waf.conf
handle_path /index.php/apps/memories/static/go-vod/* {
reverse_proxy go-vod:8080
}
handle_path /whiteboard/* {
reverse_proxy http://nextcloud-whiteboard-server:3002
}
reverse_proxy nextcloud-app:80 {
header_up Host {host}
}
}
}
http://local.poppyglen.cc {
reverse_proxy nextcloud-app:80 {
header_up Host {host}
}
log {
output file /data/caddy_access.log
}
}
vault.poppyglen.cc {
route {
coraza_waf /etc/caddy/waf/coraza.conf
reverse_proxy vaultwarden:80
}
}
office.poppyglen.cc {
reverse_proxy collabora:9980 {
header_up Host {host}
}
}
whiteboard.poppyglen.cc {
reverse_proxy nextcloud-whiteboard-server:3002 {
header_up Host {host}
header_up X-Real-IP {remote}
}
}
signal.poppyglen.cc {
log {
output file /var/log/caddy/signaling.log
}
reverse_proxy nc-talk:8081 {
header_up Host {host}
header_up X-Real-IP {remote_ip}
}
}
mail.poppyglen.cc {
respond "Mail server for poppyglen.cc"
}
immich.poppyglen.cc {
route {
import authelia
coraza_waf /etc/caddy/waf/coraza.conf
reverse_proxy immich-server:2283 {
header_up X-Real-IP {remote_ip}
}
}
}
jellyfin.poppyglen.cc {
route {
import authelia
coraza_waf /etc/caddy/waf/coraza.conf
reverse_proxy jellyfin:8096
}
}
sunshine.poppyglen.cc {
reverse_proxy https://sunshine:47990 {
transport http {
tls_insecure_skip_verify
}
}
}

13
caddy/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
# Stage 1: Build the custom Caddy binary using the official builder image
FROM caddy:builder AS builder
RUN xcaddy build \
--with github.com/corazawaf/coraza-caddy \
--with github.com/pberkel/caddy-storage-redis \
--with github.com/caddy-dns/cloudflare
# Stage 2: Create the final, clean image using the standard Caddy image
FROM caddy:latest
# Copy the custom-built Caddy binary from the builder stage
COPY --from=builder /usr/bin/caddy /usr/bin/caddy

7
caddy/waf/coraza.conf Normal file
View File

@@ -0,0 +1,7 @@
# Main Coraza WAF Configuration (Strict)
# 1. Load the OWASP setup file
Include /etc/caddy/waf/owasp-crs/crs-setup.conf
# 2. Load all the OWASP rule files
Include /etc/caddy/waf/owasp-crs/rules/*.conf

View File

@@ -0,0 +1,19 @@
# Nextcloud-Specific Exclusions
# These rules modify or remove the rules loaded from the main set.
# Rule 911100: Whitelist methods needed by WebDAV and Nextcloud APIs
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'PROPFIND'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'PUT'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'DELETE'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'REPORT'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'MKCOL'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'COPY'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'MOVE'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'LOCK'
SecRuleUpdateTargetById 911100 !REQUEST_METHOD:'UNLOCK'
# Rule 920420: Allow content types used by Nextcloud that are sometimes blocked.
SecRuleRemoveById 920420
# Rule 942550: Disable a SQL injection rule that has frequent false positives.
SecRuleRemoveById 942550

View File

@@ -0,0 +1,7 @@
# Custom WAF Configuration for Nextcloud
# 1. Load the main, strict rules first
Include /etc/caddy/waf/coraza.conf
# 2. THEN, load the Nextcloud-specific exceptions
Include /etc/caddy/waf/nextcloud-exclusions.conf

799
docker-compose.yml Normal file
View File

@@ -0,0 +1,799 @@
networks:
nextcloud-net:
driver: bridge
enable_ipv6: true # <-- Enable IPv6 for this network
ipam:
driver: default
config:
- subnet: 172.16.0.0/16 # <-- Define your desired IPv4 subnet
- subnet: "fd00:22::/64" # <-- Define your desired IPv6 subnet
#sunshine_net:
# driver: macvlan
# driver_opts:
# parent: enp102s0f3u1u4 # Your physical network card
# ipam:
# config:
# - subnet: 192.168.0.0/24 # Your network's subnet
# gateway: 192.168.0.1 # Your network's gateway
services:
minio:
image: minio/minio:latest
container_name: minio
restart: unless-stopped
environment:
# IMPORTANT: Add these to your .env file
- MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
- MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
volumes:
- /mnt/Nextcloud/minio-data:/data
ports:
# Port for the S3 API endpoint (internal access, no need to publish)
# - "9000:9000"
# Port for the MinIO web console (publish to access from your browser)
- "9001:9001"
command: server /data --console-address ":9001"
networks:
- nextcloud-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
minio-init:
image: minio/mc
container_name: minio-init
depends_on:
minio:
condition: service_healthy # Wait for MinIO to be healthy
environment:
# Pass the credentials from your .env file
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
entrypoint: /bin/sh
command: /init-minio.sh
volumes:
- ./init-minio.sh:/init-minio.sh # Mount the script
networks:
- nextcloud-net
restart: "no"
authelia:
image: authelia/authelia:latest
container_name: authelia
restart: unless-stopped
volumes:
- ./authelia:/config
networks:
- nextcloud-net
expose:
- 9091
environment:
- TZ=America/Los_Angeles
depends_on:
mail:
condition: service_started
authelia-redis:
condition: service_started
authelia-redis:
image: redis:alpine
container_name: authelia-redis
restart: unless-stopped
volumes:
- /mnt/Nextcloud/authelia-redis:/data
networks:
- nextcloud-net
cloudflare-ddns:
image: docker.io/oznu/cloudflare-ddns:latest
container_name: cloudflare_ddns
restart: unless-stopped
environment:
- API_KEY=${CF_API_KEY}
- ZONE=${CF_ZONE}
- SUBDOMAIN=${CF_SUBDOMAIN}
- PROXIED=${CF_PROXIED}
networks:
- nextcloud-net
db:
image: postgres:16
container_name: nextcloud-db
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
environment:
- TZ=America/Los_Angeles
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- DB_STORAGE_TYPE='HDD'
volumes:
- /mnt/Nextcloud/nextcloud_db:/var/lib/postgresql/data
networks:
- nextcloud-net
app:
build: ./nextcloud
container_name: nextcloud-app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
collabora:
condition: service_started
minio-init:
condition: service_completed_successfully
environment:
POSTGRES_HOST: db
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
REDIS_HOST: redis
NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER}
NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: cloud.poppyglen.cc local.poppyglen.cc
OVERWRITEHOST: cloud.poppyglen.cc
OVERWRITEPROTOCOL: https
OVERWRITECLIURL: https://cloud.poppyglen.cc
OVERWRITECONDADDR: 172.16.0.0\/12
TRUSTED_PROXIES: 172.16.0.0/12
USERS_JSON: ${USERS_JSON}
HOME: /var/www # Set HOME for www-data
GIPHY_API_KEY: ${GIPHY_API_KEY}
WHITEBOARD_JWT: ${WHITEBOARD_JWT}
TURN_SECRET: ${TURN_SECRET}
SIGNALING_SECRET: ${SIGNALING_SECRET}
MAIL_FROM_ADDRESS: admin
MAIL_DOMAIN: ${MAIL_DOMAIN}
MAIL_SMTPAUTH: 1
MAIL_SMTPSECURE: ssl
MAIL_SMTPHOST: ${MAIL_SMTPHOST}
MAIL_SMTPPORT: 465
MAIL_SMTPNAME: ${MAIL_ADMIN_EMAIL}
MAIL_SMTPPASSWORD: ${MAIL_ADMIN_PASSWORD}
MAIL_ADMIN_EMAIL: ${MAIL_ADMIN_EMAIL}
MAIL_ADMIN_PASSWORD: ${MAIL_ADMIN_PASSWORD}
EMAIL_IMAP_HOST: ${MAIL_SMTPHOST}
EMAIL_SMTP_HOST: ${MAIL_SMTPHOST}
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
volumes:
- /mnt/Nextcloud/Nextcloud:/var/www/html
- ./hooks:/docker-entrypoint-hooks.d
- /mnt/Nextcloud/music:/music
- /mnt/Nextcloud/tvshows:/tvshows
- /mnt/Nextcloud/games:/games
- /mnt/Nextcloud/movies:/movies
- /mnt/Nextcloud/photos:/photos
networks:
- nextcloud-net
cron:
image: nextcloud:latest
container_name: nextcloud-cron
restart: unless-stopped
depends_on:
- app
volumes:
- /mnt/Nextcloud/Nextcloud:/var/www/html
entrypoint: /cron.sh
networks:
- nextcloud-net
#create 32 character password fpr each service
#openssl rand -hex 32
nc-talk:
image: ghcr.io/nextcloud-releases/aio-talk:latest
container_name: nc-talk
init: true
restart: unless-stopped
ports:
- 3478:3478/tcp
- 3478:3478/udp
- 8181:8081/tcp
environment:
- NC_DOMAIN=cloud.poppyglen.cc
- TALK_HOST=signal.poppyglen.cc
- TURN_SECRET=${TURN_SECRET}
- SIGNALING_SECRET=${SIGNALING_SECRET}
- TZ=America/Los_Angeles
- TALK_PORT=3478
- RECORDING_SECRET=${RECORDING_SECRET}
- INTERNAL_SECRET=${INTERNAL_SECRET}
depends_on:
- app
networks:
- nextcloud-net
collabora:
image: collabora/code
container_name: collabora
restart: unless-stopped
networks:
- nextcloud-net
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:9980/hosting/capabilities || exit 1"]
interval: 30s
timeout: 10s
retries: 3
environment:
#- PUID=1000
#- PGID=1000
- TZ=America/Los_Angeles
- password=${COLLABORA_PASSWORD}
- username=${COLLABORA_USERNAME}
- server_name=office.poppyglen.cc
- aliasgroup1=https://cloud.poppyglen.cc:443
- aliasgroup2=http://local.poppyglen.cc
- extra_params=--o:ssl.enable=false --o:ssl.termination=true
- DONT_GEN_PASSWD=1
#ports:
# - 9980:9980
#volumes:
# - /mnt/Nextcloud/Nextcloud:/var/www/html:ro
cap_add:
- SYS_ADMIN
redis:
image: docker.io/library/redis:alpine
container_name: nextcloud-redis
restart: unless-stopped
mem_limit: 2048m
mem_reservation: 512m
volumes:
- /mnt/Nextcloud/redis:/data
networks:
- nextcloud-net
#docker compose exec caddy caddy fmt --overwrite /etc/caddy/Caddyfile
caddy:
build: ./caddy
container_name: caddy
restart: unless-stopped
env_file: .env
environment:
- CF_API_KEY=${CF_API_KEY}
ports:
- 80:80
- 443:443
- "443:443/udp"
volumes:
- /mnt/Nextcloud/Nextcloud:/var/www/html:ro
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
#- /mnt/Nextcloud/caddy/data:/data
#- /mnt/Nextcloud/caddy/config:/config
- ./caddy/waf:/etc/caddy/waf
#- /mnt/Nextcloud/caddy/logs:/var/log/caddy
networks:
- nextcloud-net
depends_on:
- caddy-redis
caddy-redis:
image: redis:alpine
container_name: caddy-redis
restart: unless-stopped
volumes:
- /mnt/Nextcloud/caddy_redis:/data
networks:
- nextcloud-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
clamav:
image: clamav/clamav:1.3
container_name: clamav
restart: unless-stopped
networks:
- nextcloud-net
volumes:
- /mnt/Nextcloud/clamav_data:/var/lib/clamav
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.15.0
container_name: elasticsearch
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health?wait_for_status=yellow || exit 1"]
interval: 30s
timeout: 10s
retries: 5
environment:
- discovery.type=single-node
- xpack.security.enabled=false # Easiest for internal Docker communication
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # Recommended to limit memory usage
volumes:
- /mnt/Nextcloud/es_data:/usr/share/elasticsearch/data
networks:
- nextcloud-net
go-vod:
image: radialapps/go-vod
container_name: go-vod
restart: always
init: true
depends_on:
- app
environment:
- NEXTCLOUD_HOST=https://cloud.poppyglen.cc
# - NEXTCLOUD_ALLOW_INSECURE=1 # (self-signed certs or no HTTPS)
- NVIDIA_VISIBLE_DEVICES=all
devices:
- /dev/dri:/dev/dri # VA-API (omit for NVENC)
volumes:
- /mnt/Nextcloud/Nextcloud:/var/www/html:ro
# runtime: nvidia # (NVENC)
networks:
- nextcloud-net
nextcloud-whiteboard-server:
image: ghcr.io/nextcloud-releases/whiteboard:stable
container_name: nextcloud-whiteboard-server
ports:
- 3002:3002
environment:
NEXTCLOUD_URL: https://cloud.poppyglen.cc
JWT_SECRET_KEY: ${WHITEBOARD_JWT}
networks:
- nextcloud-net
cert-exporter:
image: redis:alpine
container_name: cert-exporter
restart: unless-stopped
networks:
- nextcloud-net
volumes:
- ./export-certs.sh:/export-certs.sh:ro
- /mnt/Nextcloud/caddy/data:/export
command: >
sh -c "apk add --no-cache jq coreutils &&
while true; do sh /export-certs.sh; sleep 12h; done"
depends_on:
caddy-redis:
condition: service_healthy
caddy:
condition: service_started
#mkdir -p /mnt/Nextcloud/mail/{maildata,mailstate,mail-logs,config,caddy}
#docker exec -it mail doveadm search -u admin@poppyglen.cc mailbox INBOX ALL
#docker exec -it mail doveadm fetch -u admin@poppyglen.cc text mailbox INBOX uid 1
mail:
image: docker.io/mailserver/docker-mailserver:latest
container_name: mail
hostname: mail.poppyglen.cc
restart: unless-stopped
environment:
#- SSL_TYPE=manual
#- SSL_CERT_PATH=/caddy-data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.poppyglen.cc/mail.poppyglen.cc.crt
#- SSL_KEY_PATH=/caddy-data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.poppyglen.cc/mail.poppyglen.cc.key
- SSL_TYPE=letsencrypt
#- SSL_CERT_PATH=/caddy-data/mail.poppyglen.cc.crt
#- SSL_KEY_PATH=/caddy-data/mail.poppyglen.cc.key
- TZ=America/Los_Angeles
- PERMIT_DOCKER=network
- DMS_DEBUG=0
- ONE_DIR=1
- ENABLE_POSTGREY=0
- ENABLE_FAIL2BAN=1
- ENABLE_CLAMAV=1
- CLAMAV_HOST=clamav
- ENABLE_SPAMASSASSIN=1
- ENABLE_OPENDKIM=1
volumes:
- /mnt/Nextcloud/mail/maildata:/var/mail
- /mnt/Nextcloud/mail/mailstate:/var/mail-state
- /mnt/Nextcloud/mail/mail-logs:/var/log/mail
- /mnt/Nextcloud/mail/config:/tmp/docker-mailserver/
- /etc/localtime:/etc/localtime:ro
- /mnt/Nextcloud/caddy/data/mail.poppyglen.cc.crt:/etc/letsencrypt/live/mail.poppyglen.cc/fullchain.pem
- /mnt/Nextcloud/caddy/data/mail.poppyglen.cc.key:/etc/letsencrypt/live/mail.poppyglen.cc/privkey.pem
ports:
- "25:25"
- "143:143"
- "465:465"
- "587:587"
- "993:993"
cap_add:
- NET_ADMIN # Required for Fail2Ban
- SYS_PTRACE
networks:
- nextcloud-net
depends_on:
- clamav
- cert-exporter
#docker exec -it mail setup config dkim
#docker exec -it mail cat /tmp/docker-mailserver/opendkim/keys/poppyglen.cc/mail.txt | awk -F'"' '/"/{print $2}' | tr -d '\n'
ollama:
image: ollama/ollama:rocm
container_name: ollama
restart: unless-stopped
volumes:
- /mnt/Nextcloud/ollama:/root/.ollama
- /lib/modules:/lib/modules:ro
- /sys/module:/sys/module:ro
networks:
- nextcloud-net
environment:
HSA_OVERRIDE_GFX_VERSION: ${HSA_OVERRIDE_GFX_VERSION}
HIP_VISIBLE_DEVICES: "0"
devices:
- /dev/kfd:/dev/kfd
- /dev/dri:/dev/dri
security_opt:
- seccomp:unconfined
cap_add:
- SYS_MODULE
- SYS_RAWIO
#docker exec -it ollama ollama pull qwen3:4b
recording-server:
image: nextcloud/aio-talk-recording
container_name: nextcloud-recording-server
restart: unless-stopped
environment:
- NEXTCLOUD_URL=https://cloud.poppyglen.cc
- NC_DOMAIN=cloud.poppyglen.cc
- NEXTCLOUD_RECORDING_USERNAME=${NEXTCLOUD_RECORDING_USERNAME}
- NEXTCLOUD_RECORDING_PASSWORD=${NEXTCLOUD_RECORDING_PASSWORD}
- RECORDING_SECRET=${RECORDING_SECRET}
- INTERNAL_SECRET=${INTERNAL_SECRET}
networks:
- nextcloud-net # Must be on the same network as other services
immich-postgres:
container_name: immich_postgres
image: tensorchord/pgvecto-rs:pg16-v0.2.0 # Required for vector search
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${IMMICH_DB_PASSWORD}
POSTGRES_USER: ${IMMICH_DB_USER}
POSTGRES_DB: ${IMMICH_DB_NAME}
DB_STORAGE_TYPE: 'HDD'
volumes:
- /mnt/Nextcloud/immich/immich_db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
networks:
- nextcloud-net
immich-redis:
container_name: immich_redis
image: redis:6.2-alpine
restart: unless-stopped
networks:
- nextcloud-net
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:release
#command: [ "start.sh", "immich" ]
extends:
file: ./immich/hwaccel.transcoding.yml
service: vaapi
restart: unless-stopped
depends_on:
immich-postgres:
condition: service_healthy
immich-redis:
condition: service_started
environment:
# This is an anchor that other services will reference
&immich-common-env
DB_HOSTNAME: immich-postgres
DB_USERNAME: ${IMMICH_DB_USER}
DB_PASSWORD: ${IMMICH_DB_PASSWORD}
DB_DATABASE_NAME: ${IMMICH_DB_NAME}
REDIS_HOSTNAME: immich-redis
JWT_SECRET: ${IMMICH_JWT_SECRET}
# You can add other Immich specific env vars here if needed
volumes:
- /mnt/Nextcloud/immich/immich_upload:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
- /mnt/Nextcloud/photos:/import:ro
networks:
- nextcloud-net
#healthcheck:
# test: ["CMD", "curl", "-f", "http://localhost:2283/api/server/ping"]
# interval: 30s
# timeout: 10s
# retries: 5
# start_period: 30s
immich-microservices:
container_name: immich_microservices
image: ghcr.io/immich-app/immich-server:release
# This command is required to run microservices
#command: [ "start.sh", "microservices" ]
extends: # uncomment this section for hardware acceleration - see https://immich.app/docs/features/ml-hardware-acceleration
file: ./immich/hwaccel.ml.yml
service: rocm # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
restart: unless-stopped
depends_on:
- immich-server
environment:
# Use the alias to inherit common environment variables
<<: *immich-common-env
volumes:
- /mnt/Nextcloud/immich/immich_upload:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
- /mnt/Nextcloud/photos:/import:ro
networks:
- nextcloud-net
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:release
restart: unless-stopped
volumes:
- /mnt/Nextcloud/immich/immich_models:/cache
environment:
# Use the alias to inherit common environment variables
<<: *immich-common-env
networks:
- nextcloud-net
immich-init:
image: alpine:3.20
container_name: immich-init
env_file: .env
environment:
IMMICH_BASE_URL: http://immich-server:2283/api
depends_on:
- immich-server
#condition: service_healthy
volumes:
- ./immich/init-immich.sh:/init-immich.sh:ro
entrypoint: ["/bin/sh", "/init-immich.sh"]
restart: "no"
networks:
- nextcloud-net
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
user: 1000:1000
environment:
- TZ=America/Los_Angeles
- PUID=1000 # Replace with your user ID
- PGID=1000 # Replace with your group ID
volumes:
- /mnt/Nextcloud/jellyfin/config:/config
- /mnt/Nextcloud/jellyfin/cache:/cache
- /mnt/Nextcloud/movies:/media/movies
- /mnt/Nextcloud/tvshows:/media/tvshows
- /mnt/Nextcloud/music:/media/music
- /mnt/Nextcloud/photos:/media/photos
ports:
- "8096:8096" # Web UI
- "7359:7359/udp" # Client discovery
- "1900:1900/udp" # DLNA
devices:
- /dev/dri:/dev/dri # For Intel Quick Sync or AMD VA-API hardware acceleration
networks:
- nextcloud-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096/Users/Public"]
interval: 15s
timeout: 5s
retries: 40
start_period: 30s
jellyfin-init:
image: alpine:3.20
container_name: jellyfin-init
env_file: .env
environment:
JELLYFIN_BASE_URL: ${JELLYFIN_BASE_URL}
JELLYFIN_INIT_ADMIN_USER: ${JELLYFIN_INIT_ADMIN_USER}
JELLYFIN_INIT_ADMIN_PASSWORD: ${JELLYFIN_INIT_ADMIN_PASSWORD}
JELLYFIN_INIT_SERVERNAME: ${JELLYFIN_INIT_SERVERNAME}
depends_on:
jellyfin:
condition: service_healthy
volumes:
- ./jellyfin/init-jellyfin.sh:/init-jellyfin.sh:ro
- /mnt/Nextcloud/movies:/media/movies
- /mnt/Nextcloud/tvshows:/media/tvshows
- /mnt/Nextcloud/music:/media/music
- /mnt/Nextcloud/photos:/media/photos
entrypoint: ["/bin/sh", "/init-jellyfin.sh"]
restart: "no"
networks:
- nextcloud-net
#sunshine:
# image: ghcr.io/lizardbyte/sunshine:v2025.628.4510-archlinux
# container_name: sunshine
# restart: unless-stopped
# privileged: true
# shm_size: "2gb"
# user: "root"
# group_add:
# - "render"
# - "video"
# - "input"
# environment:
# - TZ=America/Los_Angeles
# - PUID=1000
# - PGID=1000
# - LIBVA_DRIVER_NAME=radeonsi
# - WAYLAND_DISPLAY=${WAYLAND_DISPLAY:-wayland-0}
# - XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/run/user/1000} # replace 1000 with your UID
# - SUNSHINE_USERNAME=${SUNSHINE_USERNAME}
# - SUNSHINE_PASSWORD=${SUNSHINE_PASSWORD}
# - DISPLAY=:1
# volumes:
# - /mnt/Nextcloud/sunshine/config:/config
# - /run/user/1000:/run/user/1000
# - /tmp/.X11-unix:/tmp/.X11-unix # optional for X11
# - /var/lib/dbus/machine-id:/var/lib/dbus/machine-id:ro
# - /run/dbus:/run/dbus:ro
# - /run/udev/data:/run/udev/data:ro
# ports:
# - "47984:47984/udp"
# - "47990:47990/tcp"
# - "47989:47989/tcp"
# - "48010:48010/udp"
# - "48010:48010/tcp"
# - "47998-48000:47998-48000/udp"
# devices:
# - /dev/dri:/dev/dri
# - /dev/input:/dev/input
# - /dev/uinput:/dev/uinput
# #networks:
# # - nextcloud-net
# networks:
# sunshine_net:
# ipv4_address: 192.168.0.200
wolf:
image: ghcr.io/games-on-whales/wolf:stable
container_name: wolf
#user: "1000:1000"
privileged: true
environment:
- XDG_RUNTIME_DIR=/tmp/sockets
- HOST_APPS_STATE_FOLDER=/mnt/Nextcloud/wolf
- WAYLAND_DISPLAY=wayland-1
- MESA_LOADER_DRIVER_OVERRIDE=amd
- VDPAU_DRIVER=va_gl
- LIBVA_DRIVER_NAME=radeonsi
- RADV_DEBUG=llvm
- WOLF_LOG_LEVEL:DEBUG
volumes:
- /mnt/Nextcloud/wolf:/mnt/Nextcloud/wolf:rw
- /mnt/Nextcloud/wolf/cfg:/etc/wolf/cfg:rw
- /run/user/1000:/run/user/1000
- /run/udev/data:/run/udev/data:ro
- /tmp/sockets:/tmp/sockets:rw
- /var/run/docker.sock:/var/run/docker.sock:rw
- /var/lib/dbus/machine-id:/var/lib/dbus/machine-id:ro
- /usr/share/vulkan/icd.d:/usr/share/vulkan/icd.d:ro
- /usr/lib/libvulkan.so:/usr/lib/libvulkan.so:ro
- /usr/lib/libvulkan.so.1:/usr/lib/libvulkan.so.1:ro
- /usr/lib/libvulkan.so.1.4.321:/usr/lib/libvulkan.so.1.4.321:ro
- /usr/lib/libvulkan_radeon.so:/usr/lib/libvulkan_radeon.so:ro
- /usr/lib/libEGL_mesa.so:/usr/lib/libEGL_mesa.so:ro
- /usr/lib/libEGL_mesa.so.0:/usr/lib/libEGL_mesa.so.0:ro
- /usr/lib/libEGL_mesa.so.0.0.0:/usr/lib/libEGL_mesa.so.0.0.0:ro
- /usr/lib/libGLX_mesa.so:/usr/lib/libGLX_mesa.so:ro
- /usr/lib/libGLX_mesa.so.0:/usr/lib/libGLX_mesa.so.0:ro
- /usr/lib/libGLX_mesa.so.0.0.0:/usr/lib/libGLX_mesa.so.0.0.0:ro
- /usr/lib/libva.so:/usr/lib/libva.so:ro
- /usr/lib/libva.so.2:/usr/lib/libva.so.2:ro
- /usr/lib/libva.so.2.0.0:/usr/lib/libva.so.2.0.0:ro
- /usr/lib/dri/radeonsi_drv_video.so:/usr/lib/dri/radeonsi_drv_video.so:ro
- /usr/lib/x86_64-linux-gnu/dri:/usr/lib/x86_64-linux-gnu/dri:ro
- /run/dbus:/run/dbus:ro
- /run/udev:/run/udev:rw
device_cgroup_rules:
- 'c 13:* rmw'
devices:
- /dev/dri:/dev/dri:rw
- /dev/dri/renderD128:/dev/dri/renderD128:rw
- /dev/uinput:/dev/uinput
- /dev/uhid:/dev/uhid
group_add:
- "989"
- "video"
- "994"
network_mode: host
restart: unless-stopped
#networks:
# sunshine_net:
# ipv4_address: 192.168.0.200
technitium-dns:
image: technitium/dns-server:latest
container_name: technitium-dns
hostname: technitium-dns
restart: unless-stopped
volumes:
- /mnt/Nextcloud/technitium/config:/etc/dns
environment:
- DNS_SERVER_DOMAIN=home.lan
- DNS_SERVER_ADMIN_PASSWORD=${TECHNITIUM_ADMIN_PASSWORD}
- DNS_SERVER_FORWARDERS=1.1.1.1,8.8.8.8,2606:4700:4700::1111,2001:4860:4860::8888
- DNS_SERVER_FORWARDER_PROTOCOL=Udp
- DNS_SERVER_RECURSION=AllowOnlyForPrivateNetworks
- DNS_SERVER_RECURSION_ALLOWED_NETWORKS=192.168.0.0/24,fd00::/8
ports:
- "5380:5380/tcp" # Web UI
- "53:53/tcp" # DNS
- "53:53/udp" # DNS
networks:
- nextcloud-net
#echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
#echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
environment:
- WEBSOCKET_ENABLED=true # Required for Caddy reverse proxy
- SIGNUPS_ALLOWED=true # Set to false after you've created your account
- ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN} # Add a secure token to your .env file
volumes:
- /mnt/Nextcloud/vaultwarden:/data
networks:
- nextcloud-net
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=America/Los_Angeles
- SERVERURL=vpn.poppyglen.cc # or your public domain, e.g., vpn.poppyglen.cc
- PEERS=1 # Number of peer configs to generate
- PEERDNS=auto
- INTERNAL_SUBNET=10.13.13.0/24
volumes:
- /mnt/Nextcloud/wireguard/config:/config
- /lib/modules:/lib/modules
ports:
- 51820:51820/udp
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
networks:
- nextcloud-net
#ipfs:
# image: ipfs/kubo:latest
# container_name: ipfs_node
# restart: unless-stopped
# environment:
# - IPFS_PROFILE=server
# volumes:
# - /mnt/Nextcloud/ipfs_data:/data/ipfs
# ports:
# - "4001:4001/tcp" # Swarm - TCP
# - "4001:4001/udp" # Swarm - QUIC
# - "8080:8080" # Gateway
# - "5001:5001" # API
# networks:
# - nextcloud-net

480
init-mail.sh Normal file
View File

@@ -0,0 +1,480 @@
#!/bin/bash
#set -euo pipefail # Exit on error, unset variables are errors
# ---------------------------
# Configuration
# ---------------------------
# Mail
MAIL_CONFIG_DIR="/mnt/Nextcloud/mail/config"
ACCOUNT_FILE="$MAIL_CONFIG_DIR/postfix-accounts.cf"
ADMIN_EMAIL="admin@poppyglen.cc"
# Caddy WAF
CADDY_WAF_DIR="./caddy/waf"
# Sunshine
SUNSHINE_CONFIG_DIR="/mnt/Nextcloud/sunshine/config"
SUNSHINE_CONFIG_FILE="$SUNSHINE_CONFIG_DIR/sunshine.conf"
SUNSHINE_USERNAME="${SUNSHINE_USERNAME:-sunshine_admin}"
SUNSHINE_PASSWORD="${SUNSHINE_PASSWORD:-}"
# Authelia
AUTHELIA_CONFIG_DIR="./authelia"
AUTHELIA_USERS_FILE="$AUTHELIA_CONFIG_DIR/users_database.yml"
AUTHELIA_CONFIG_FILE="$AUTHELIA_CONFIG_DIR/configuration.yml"
AUTHELIA_REDIS_DIR="/mnt/Nextcloud/authelia-redis"
# MinIO
MINIO_DATA_DIR="/mnt/Nextcloud/minio-data"
# ---------------------------
# General Functions
# ---------------------------
require_root() {
if [[ "$(id -u)" -ne 0 ]]; then
echo "❌ Error: This script must be run as root or with sudo." >&2
exit 1
fi
}
load_env() {
if [[ -f ".env" ]]; then
echo "📄 Loading environment variables from .env..."
while IFS='=' read -r key value; do
[[ -z "$key" || "$key" =~ ^# || "$key" =~ \[|\{ ]] && continue
export "$key=$value"
done < .env
fi
}
# ---------------------------
# Mail Setup Functions
# ---------------------------
get_password() {
if [[ -z "${MAIL_ADMIN_PASSWORD:-}" ]]; then
read -sp "Enter a password for the mail admin ($ADMIN_EMAIL): " MAIL_ADMIN_PASSWORD
echo
else
echo "✅ Loaded MAIL_ADMIN_PASSWORD from .env"
fi
if [[ -z "$MAIL_ADMIN_PASSWORD" ]]; then
echo "❌ Error: Password cannot be empty." >&2
exit 1
fi
}
generate_hash() {
local password="$1"
docker run --rm docker.io/mailserver/docker-mailserver:latest \
doveadm pw -s SHA512-CRYPT -p "$password"
}
create_account_file() {
echo "📝 Creating account file: $ACCOUNT_FILE"
mkdir -p "$MAIL_CONFIG_DIR"
echo "$ADMIN_EMAIL|$HASH" > "$ACCOUNT_FILE"
# Add additional users from USERS_JSON
if [[ -n "${USERS_JSON:-}" ]]; then
echo "📋 Adding additional users from USERS_JSON..."
echo "$USERS_JSON" | jq -c '.[]' | while read -r user; do
username=$(echo "$user" | jq -r '.username')
password=$(echo "$user" | jq -r '.password')
if [[ -z "$username" || -z "$password" ]]; then
echo "⚠️ Skipping invalid user entry: $user"
continue
fi
user_hash=$(generate_hash "$password")
echo "$username@$MAIL_DOMAIN|$user_hash" >> "$ACCOUNT_FILE"
echo " Added user: $username@$MAIL_DOMAIN"
done
fi
}
setup_mail() {
echo "📧 Mail Server First-Time Setup..."
if [[ -f "$ACCOUNT_FILE" ]]; then
read -p "⚠️ A mail account file already exists. Overwrite? (y/N) " -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "Skipping mail setup."
return
fi
fi
get_password
HASH=$(generate_hash "$MAIL_ADMIN_PASSWORD")
create_account_file
echo "✅ Mail setup complete."
}
# ---------------------------
# Sunshine Config Setup
# ---------------------------
setup_sunshine_config() {
echo "☀️ Setting up Sunshine config..."
mkdir -p "$SUNSHINE_CONFIG_DIR"
if [[ -f "$SUNSHINE_CONFIG_FILE" ]]; then
read -p "⚠️ Sunshine config already exists. Overwrite? (y/N) " -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "Skipping Sunshine config setup."
return
fi
rm "$SUNSHINE_CONFIG_FILE"
fi
local password="$SUNSHINE_PASSWORD"
if [[ -z "$password" ]]; then
read -sp "Enter a password for Sunshine user ($SUNSHINE_USERNAME): " password
echo
fi
if [[ -z "$password" ]]; then
echo "❌ Error: Sunshine password cannot be empty." >&2
exit 1
fi
echo "🔐 Creating Sunshine credentials..."
docker compose run --rm sunshine --creds "$SUNSHINE_USERNAME" "$password"
sed -i '1i username = "'"$SUNSHINE_USERNAME"'"' "$SUNSHINE_CONFIG_FILE"
echo "🔧 Setting permissions for Sunshine config..."
chown -R 1000:1000 "$SUNSHINE_CONFIG_DIR"
echo "✅ Sunshine config created successfully!"
}
# ---------------------------
# Caddy WAF Setup
# ---------------------------
setup_caddy_waf() {
echo "🛡️ Setting up Caddy WAF..."
if ! command -v git &> /dev/null; then
echo "❌ Error: git is not installed. Please install git to continue." >&2
exit 1
fi
mkdir -p "$CADDY_WAF_DIR"
local owasp_crs_dir="$CADDY_WAF_DIR/owasp-crs"
if [[ -d "$owasp_crs_dir" ]]; then
echo "✅ OWASP Core Rule Set already exists. Skipping clone."
else
echo "⏳ Cloning OWASP Core Rule Set..."
git clone https://github.com/coreruleset/coreruleset.git "$owasp_crs_dir"
fi
local crs_setup_conf="$owasp_crs_dir/crs-setup.conf"
if [[ ! -f "$crs_setup_conf" ]]; then
echo "📝 Creating crs-setup.conf from example..."
cp "$owasp_crs_dir/crs-setup.conf.example" "$crs_setup_conf"
fi
local coraza_conf="$CADDY_WAF_DIR/coraza.conf"
if [[ -f "$coraza_conf" ]]; then
echo "✅ coraza.conf already exists. Skipping."
else
echo "📝 Creating main WAF configuration (coraza.conf)..."
cat <<EOF > "$coraza_conf"
# This file tells Coraza where to find the OWASP Core Rule Set.
Include @owasp_crs/crs-setup.conf
Include @owasp_crs/rules/*.conf
EOF
fi
echo "✅ Caddy WAF setup is complete!"
}
# ---------------------------
# Authelia Setup
# ---------------------------
generate_authelia_hash() {
local pass="$1"
local output
output=$(docker run --rm authelia/authelia authelia crypto hash generate argon2 --password "$pass" 2>&1)
echo "$output" | grep -o '\$argon2id\$.*'
}
setup_authelia() {
echo "🔐 Setting up Authelia..."
if ! command -v openssl &> /dev/null; then
echo "❌ Error: openssl is not installed. Please install it to generate secure secrets." >&2
exit 1
fi
mkdir -p "$AUTHELIA_CONFIG_DIR"
if [[ -f "$AUTHELIA_USERS_FILE" ]]; then
read -p "⚠️ Authelia user database already exists. Overwrite? (y/N) " -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "Skipping Authelia setup."
return
fi
fi
# --- Admin User Setup ---
local admin_username="${AUTHELIA_ADMIN_USER:-}"
local admin_password="${AUTHELIA_ADMIN_PASSWORD:-}"
if [[ -z "$admin_username" ]]; then
read -p "Enter a username for the Authelia admin: " admin_username
else
echo "✅ Loaded AUTHELIA_ADMIN_USER from .env"
fi
if [[ -z "$admin_password" ]]; then
read -sp "Enter a password for Authelia user '$admin_username': " admin_password
echo
else
echo "✅ Loaded AUTHELIA_ADMIN_PASSWORD from .env"
fi
if [[ -z "$admin_username" || -z "$admin_password" ]]; then
echo "❌ Error: Authelia admin username and password cannot be empty." >&2
exit 1
fi
echo "⏳ Generating password hash for admin user..."
local admin_hash
admin_hash=$(generate_authelia_hash "$admin_password")
if [[ -z "$admin_hash" ]]; then
echo "❌ Error: Could not generate a valid hash for the admin user." >&2
exit 1
fi
# --- Authelia Configuration File Generation ---
echo "⏳ Generating secrets..."
local session_secret
session_secret=$(openssl rand -hex 32)
local encryption_key
encryption_key=$(openssl rand -hex 32)
local jwt_secret
jwt_secret=$(openssl rand -hex 32)
echo "📝 Creating Authelia configuration file..."
cat <<EOF > "$AUTHELIA_CONFIG_FILE"
# Main server configuration
server:
address: tcp://0.0.0.0:9091
# Session configuration using modern format
session:
secret: "$session_secret"
cookies:
- name: poppy_session
domain: poppyglen.cc
authelia_url: https://auth.poppyglen.cc
# Use Redis for session storage for better performance
redis:
host: authelia-redis
port: 6379
# Storage for user data, password reset tokens, etc.
storage:
encryption_key: "$encryption_key"
# Use a local SQLite database for persistent storage
local:
path: /config/db.sqlite3
# User authentication backend
authentication_backend:
file:
path: /config/users_database.yml
# Access control rules
access_control:
default_policy: deny
rules:
- domain: "cloud.poppyglen.cc"
policy: bypass
resources:
- '^/index\.php/apps/memories/static/go-vod\?arch=.+$'
methods: [GET]
- domain: "cloud.poppyglen.cc"
policy: bypass
resources:
- '^/apps/circles/async/.*$'
methods: [GET]
- domain: "cloud.poppyglen.cc"
policy: bypass
resources:
- '^/index\.php/apps/richdocuments/wopi/.*$'
- domain: "cloud.poppyglen.cc"
policy: bypass
resources:
- '^/\.well-known/(card|cal)dav$'
- domain: "cloud.poppyglen.cc"
policy: bypass
resources:
- '^/remote\.php/(dav|webdav)/.*$'
- domain: "cloud.poppyglen.cc"
policy: bypass
resources:
- '^/ocs/v[12]\.php/.*$'
- '^/remote\.php/status\.php$'
- domain:
- "cloud.poppyglen.cc"
- "immich.poppyglen.cc"
- "jellyfin.poppyglen.cc"
policy: two_factor
subject:
- "group:admins"
- "group:users"
- "group:family"
- domain: "auth.poppyglen.cc"
policy: bypass
# Required for password reset functionality
identity_validation:
reset_password:
jwt_secret: "$jwt_secret"
# Notification settings
notifier:
disable_startup_check: true
smtp:
address: "submission://mail:587"
username: $MAIL_ADMIN_EMAIL
password: $MAIL_ADMIN_PASSWORD
sender: "Authelia <admin@poppyglen.cc>"
identifier: "authelia.poppyglen.cc"
tls:
skip_verify: true
# disable_require_tls: false
# filesystem:
# filename: /config/notification.log
EOF
# --- Authelia User Database File Generation ---
echo "📝 Creating Authelia user database for admin..."
{
echo "users:"
echo " $admin_username:"
echo " displayname: \"Admin User\""
echo " password: '$admin_hash'"
echo " email: \"admin@poppyglen.cc\""
echo " groups:"
echo " - admins"
} > "$AUTHELIA_USERS_FILE"
# --- START: New section to add users from JSON ---
if [[ -n "${USERS_JSON:-}" ]]; then
echo "📋 Adding additional Authelia users from USERS_JSON..."
echo "$USERS_JSON" | jq -c '.[]' | while read -r user_json; do
local username=$(echo "$user_json" | jq -r '.username')
local password=$(echo "$user_json" | jq -r '.password')
local name=$(echo "$user_json" | jq -r '.name')
local email=$(echo "$user_json" | jq -r '.email')
if [[ -z "$username" || -z "$password" ]]; then
echo "⚠️ Skipping invalid user entry: $user_json"
continue
fi
echo "⏳ Generating password hash for user '$username'..."
local user_hash
user_hash=$(generate_authelia_hash "$password")
if [[ -z "$user_hash" ]]; then
echo "❌ Error: Could not generate a valid hash for user '$username'." >&2
continue
fi
# Append the new user to the users_database.yml file
{
echo " $username:"
echo " displayname: \"$name\""
echo " password: '$user_hash'"
echo " email: \"$email\""
echo " groups:"
echo " - users"
echo " - family"
} >> "$AUTHELIA_USERS_FILE"
echo " Added Authelia user: $username"
done
fi
# --- END: New section ---
echo "✅ Authelia setup is complete!"
}
# ---------------------------
# Cleanup Function
# ---------------------------
clean_services() {
local COMPOSE_FILE="docker-compose.yml"
if [[ ! -f "$COMPOSE_FILE" ]]; then
echo "❌ Error: $COMPOSE_FILE not found in the current directory." >&2
exit 1
fi
echo "This script will PERMANENTLY DELETE data for the selected services."
read -p "Are you sure you want to proceed with cleanup? (y/N) " -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "Operation cancelled."
exit 0
fi
echo "⬇️ Bringing down Docker containers and networks..."
docker compose down --remove-orphans
# Helper function to clean directories
_clean_dir_contents() {
local service_name="$1"
shift
local dirs_to_clean=("$@")
read -p "Do you want to delete ALL data for $service_name? (y/N) " -r clean_response
if [[ "$clean_response" =~ ^[Yy]$ ]]; then
echo "🗑️ Cleaning $service_name directories..."
for vol in "${dirs_to_clean[@]}"; do
if [[ -d "$vol" ]]; then
echo "Cleaning host directory: $vol"
find "$vol" -mindepth 1 -delete
else
echo " -> Directory not found, skipping."
fi
done
echo "$service_name data has been cleared."
else
echo "Skipping $service_name data cleanup."
fi
}
_clean_dir_contents "Authelia" "$AUTHELIA_CONFIG_DIR" "$AUTHELIA_REDIS_DIR"
_clean_dir_contents "Nextcloud Core" "/mnt/Nextcloud/Nextcloud" "/mnt/Nextcloud/nextcloud_db" "/mnt/Nextcloud/redis" "/mnt/Nextcloud/clamav_data" "/mnt/Nextcloud/es_data"
_clean_dir_contents "MinIO S3 Storage" "$MINIO_DATA_DIR"
_clean_dir_contents "Immich" "/mnt/Nextcloud/immich/immich_db" "/mnt/Nextcloud/immich/immich_upload" "/mnt/Nextcloud/immich/immich_models"
_clean_dir_contents "Jellyfin" "/mnt/Nextcloud/jellyfin/config" "/mnt/Nextcloud/jellyfin/cache"
_clean_dir_contents "Mail Server" "/mnt/Nextcloud/mail/maildata" "/mnt/Nextcloud/mail/mailstate" "/mnt/Nextcloud/mail/mail-logs" "/mnt/Nextcloud/mail/config"
_clean_dir_contents "Sunshine" "/mnt/Nextcloud/sunshine"
_clean_dir_contents "Technitium DNS" "/mnt/Nextcloud/technitium/config"
_clean_dir_contents "Ollama" "/mnt/Nextcloud/ollama"
_clean_dir_contents "Caddy (Redis Data)" "/mnt/Nextcloud/caddy_redis"
echo "✅ Cleanup complete."
}
# ---------------------------
# Main Execution
# ---------------------------
main() {
require_root
if [[ "${1:-}" == "clean" ]]; then
clean_services
else
echo "🚀 Services First-Time Setup Script"
echo "------------------------------------"
load_env
# --- Run Setup Functions ---
setup_mail
setup_caddy_waf
setup_authelia
setup_sunshine_config
echo "------------------------------------"
echo "✅ All setups complete! You can now run: docker compose up -d"
echo "To clean up this setup, run: sudo ./init-services.sh clean"
fi
}
main "$@"