From 1f7ed5071d58fed7f28302b1af8b0614d077a392 Mon Sep 17 00:00:00 2001 From: Eduardo David Paredes Vara Date: Tue, 17 Mar 2026 15:30:01 +0000 Subject: [PATCH] stacks env --- nextcloud/docker-compose.yml | 167 +++++++++++++++++++++++++++++++++++ nextcloud/stack.env | 13 +++ paperless/docker-compose.yml | 167 +++++++++++++++++++++++++++++++++++ paperless/stack.env | 19 ++++ 4 files changed, 366 insertions(+) create mode 100644 nextcloud/docker-compose.yml create mode 100644 nextcloud/stack.env create mode 100644 paperless/docker-compose.yml create mode 100644 paperless/stack.env diff --git a/nextcloud/docker-compose.yml b/nextcloud/docker-compose.yml new file mode 100644 index 0000000..25b6b54 --- /dev/null +++ b/nextcloud/docker-compose.yml @@ -0,0 +1,167 @@ +services: + nextcloud-db: + image: mariadb:lts + container_name: nextcloud-db + restart: unless-stopped + command: > + --transaction-isolation=READ-COMMITTED + --binlog-format=ROW + --character-set-server=utf8mb4 + --collation-server=utf8mb4_general_ci + environment: + TZ: ${TZ} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: ${MYSQL_DATABASE} + MYSQL_USER: ${MYSQL_USER} + MYSQL_PASSWORD: ${MYSQL_PASSWORD} + volumes: + - /opt/nextcloud/db:/var/lib/mysql:Z + networks: + - nextcloud_internal + + nextcloud-redis: + image: redis:7-alpine + container_name: nextcloud-redis + restart: unless-stopped + command: redis-server --save 60 1 --loglevel warning + environment: + TZ: ${TZ} + volumes: + - /opt/nextcloud/redis:/data:Z + networks: + - nextcloud_internal + + nextcloud: + image: nextcloud:33-apache + container_name: nextcloud + restart: unless-stopped + depends_on: + - nextcloud-db + - nextcloud-redis + environment: + TZ: ${TZ} + MYSQL_HOST: nextcloud-db + MYSQL_DATABASE: ${MYSQL_DATABASE} + MYSQL_USER: ${MYSQL_USER} + MYSQL_PASSWORD: ${MYSQL_PASSWORD} + REDIS_HOST: nextcloud-redis + + NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER} + NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD} + NEXTCLOUD_TRUSTED_DOMAINS: ${NC_DOMAIN} nextcloud localhost + + TRUSTED_PROXIES: ${TRUSTED_PROXIES} + OVERWRITEHOST: ${NC_DOMAIN} + OVERWRITEPROTOCOL: https + OVERWRITECLIURL: https://${NC_DOMAIN} + + PHP_MEMORY_LIMIT: 2048M + PHP_UPLOAD_LIMIT: 16G + volumes: + - /opt/nextcloud/html:/var/www/html:Z + - /opt/nextcloud/config:/var/www/html/config:Z + - /opt/nextcloud/data:/var/www/html/data:Z + - /opt/nextcloud/custom_apps:/var/www/html/custom_apps:Z + - /opt/nextcloud/themes:/var/www/html/themes:Z + + # Opcional: exponer archivo final de Paperless en Nextcloud como solo lectura + - /opt/paperless/media:/mnt/paperless-media:ro,Z + networks: + - nextcloud_internal + - proxy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + + - traefik.http.routers.nextcloud.rule=Host(`${NC_DOMAIN}`) + - traefik.http.routers.nextcloud.entrypoints=websecure + - traefik.http.routers.nextcloud.tls=true + - traefik.http.routers.nextcloud.tls.certresolver=${TRAEFIK_CERTRESOLVER} + - traefik.http.routers.nextcloud.middlewares=nc-dav,nc-secure-headers + + - traefik.http.middlewares.nc-dav.redirectregex.permanent=true + - traefik.http.middlewares.nc-dav.redirectregex.regex=https://(.*)/.well-known/(?:card|cal)dav + - traefik.http.middlewares.nc-dav.redirectregex.replacement=https://$${1}/remote.php/dav + + - traefik.http.middlewares.nc-secure-headers.headers.stsSeconds=31536000 + - traefik.http.middlewares.nc-secure-headers.headers.stsIncludeSubdomains=true + - traefik.http.middlewares.nc-secure-headers.headers.stsPreload=true + - traefik.http.middlewares.nc-secure-headers.headers.contentTypeNosniff=true + - traefik.http.middlewares.nc-secure-headers.headers.browserXssFilter=true + + - traefik.http.services.nextcloud.loadbalancer.server.port=80 + + nextcloud-cron: + image: nextcloud:33-apache + container_name: nextcloud-cron + restart: unless-stopped + depends_on: + - nextcloud + entrypoint: /cron.sh + environment: + TZ: ${TZ} + MYSQL_HOST: nextcloud-db + MYSQL_DATABASE: ${MYSQL_DATABASE} + MYSQL_USER: ${MYSQL_USER} + MYSQL_PASSWORD: ${MYSQL_PASSWORD} + REDIS_HOST: nextcloud-redis + volumes: + - /opt/nextcloud/html:/var/www/html:Z + - /opt/nextcloud/config:/var/www/html/config:Z + - /opt/nextcloud/data:/var/www/html/data:Z + - /opt/nextcloud/custom_apps:/var/www/html/custom_apps:Z + - /opt/nextcloud/themes:/var/www/html/themes:Z + + # Opcional: exponer archivo final de Paperless en Nextcloud como solo lectura + - /opt/paperless/media:/mnt/paperless-media:ro,Z + networks: + - nextcloud_internal + + onlyoffice-documentserver: + image: onlyoffice/documentserver:9.3.1 + container_name: onlyoffice-documentserver + restart: unless-stopped + environment: + TZ: ${TZ} + JWT_ENABLED: "true" + JWT_SECRET: ${OO_JWT_SECRET} + JWT_HEADER: Authorization + SECURE_LINK_SECRET: ${OO_SECURE_LINK_SECRET} + ALLOW_PRIVATE_IP_ADDRESS: "true" + volumes: + - /opt/onlyoffice/logs:/var/log/onlyoffice:Z + - /opt/onlyoffice/data:/var/www/onlyoffice/Data:Z + - /opt/onlyoffice/lib:/var/lib/onlyoffice:Z + - /opt/onlyoffice/postgresql:/var/lib/postgresql:Z +#- /opt/onlyoffice/plugins:/var/www/onlyoffice/documentserver/sdkjs-plugins:Z + networks: + - nextcloud_internal + - proxy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + + - traefik.http.routers.onlyoffice.rule=Host(`${OO_DOMAIN}`) + - traefik.http.routers.onlyoffice.entrypoints=websecure + - traefik.http.routers.onlyoffice.tls=true + - traefik.http.routers.onlyoffice.tls.certresolver=${TRAEFIK_CERTRESOLVER} + - traefik.http.routers.onlyoffice.middlewares=oo-secure-headers,oo-forwarded + + - traefik.http.middlewares.oo-secure-headers.headers.stsSeconds=31536000 + - traefik.http.middlewares.oo-secure-headers.headers.stsIncludeSubdomains=true + - traefik.http.middlewares.oo-secure-headers.headers.stsPreload=true + - traefik.http.middlewares.oo-secure-headers.headers.contentTypeNosniff=true + + - traefik.http.middlewares.oo-forwarded.headers.customRequestHeaders.X-Forwarded-Proto=https + - traefik.http.middlewares.oo-forwarded.headers.customRequestHeaders.X-Forwarded-Host=${OO_DOMAIN} + - traefik.http.middlewares.oo-forwarded.headers.customRequestHeaders.X-Forwarded-Port=443 + - traefik.http.middlewares.oo-forwarded.headers.customRequestHeaders.X-Forwarded-Ssl=on + + - traefik.http.services.onlyoffice.loadbalancer.server.port=80 + +networks: + nextcloud_internal: + driver: bridge + + proxy: + external: true diff --git a/nextcloud/stack.env b/nextcloud/stack.env new file mode 100644 index 0000000..d6a984b --- /dev/null +++ b/nextcloud/stack.env @@ -0,0 +1,13 @@ +TZ=Europe/Madrid +NC_DOMAIN=nextcloud.example.com +OO_DOMAIN=onlyoffice.example.com +TRAEFIK_CERTRESOLVER=letsencrypt +TRUSTED_PROXIES=10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 +MYSQL_ROOT_PASSWORD=change_me_mysql_root_password_long_and_secure +MYSQL_DATABASE=nextcloud +MYSQL_USER=nextcloud +MYSQL_PASSWORD=change_me_nextcloud_db_password_long_and_secure +NEXTCLOUD_ADMIN_USER=admin +NEXTCLOUD_ADMIN_PASSWORD=change_me_nextcloud_admin_password_long_and_secure +OO_JWT_SECRET=change_me_onlyoffice_jwt_secret_long_and_random +OO_SECURE_LINK_SECRET=change_me_onlyoffice_secure_link_secret_long_and_random diff --git a/paperless/docker-compose.yml b/paperless/docker-compose.yml new file mode 100644 index 0000000..32db056 --- /dev/null +++ b/paperless/docker-compose.yml @@ -0,0 +1,167 @@ +services: + paperless-db: + image: postgres:18 + container_name: paperless-db + restart: unless-stopped + environment: + TZ: ${TZ} + POSTGRES_DB: ${PAPERLESS_DBNAME} + POSTGRES_USER: ${PAPERLESS_DBUSER} + POSTGRES_PASSWORD: ${PAPERLESS_DBPASS} + volumes: + - /opt/paperless/pgdata:/var/lib/postgresql:Z + networks: + - paperless_internal + + paperless-redis: + image: redis:8 + container_name: paperless-redis + restart: unless-stopped + volumes: + - /opt/paperless/redis:/data:Z + networks: + - paperless_internal + + paperless-gotenberg: + image: gotenberg/gotenberg:8.27 + container_name: paperless-gotenberg + restart: unless-stopped + command: + - "gotenberg" + - "--chromium-disable-javascript=true" + - "--chromium-allow-list=file:///tmp/.*" + networks: + - paperless_internal + + paperless-tika: + image: apache/tika:latest + container_name: paperless-tika + restart: unless-stopped + networks: + - paperless_internal + + paperless: + image: ghcr.io/paperless-ngx/paperless-ngx:latest + container_name: paperless + restart: unless-stopped + depends_on: + - paperless-db + - paperless-redis + - paperless-gotenberg + - paperless-tika + environment: + TZ: ${TZ} + + PAPERLESS_REDIS: redis://paperless-redis:6379 + PAPERLESS_DBHOST: paperless-db + PAPERLESS_DBENGINE: postgresql + PAPERLESS_DBNAME: ${PAPERLESS_DBNAME} + PAPERLESS_DBUSER: ${PAPERLESS_DBUSER} + PAPERLESS_DBPASS: ${PAPERLESS_DBPASS} + + PAPERLESS_URL: https://${PAPERLESS_DOMAIN} + PAPERLESS_SECRET_KEY: ${PAPERLESS_SECRET_KEY} + PAPERLESS_ALLOWED_HOSTS: ${PAPERLESS_ALLOWED_HOSTS} + PAPERLESS_CSRF_TRUSTED_ORIGINS: https://${PAPERLESS_DOMAIN} + PAPERLESS_TRUSTED_PROXIES: ${TRUSTED_PROXIES} + + PAPERLESS_ADMIN_USER: ${PAPERLESS_ADMIN_USER} + PAPERLESS_ADMIN_PASSWORD: ${PAPERLESS_ADMIN_PASSWORD} + PAPERLESS_ADMIN_MAIL: ${PAPERLESS_ADMIN_MAIL} + + PAPERLESS_TIKA_ENABLED: 1 + PAPERLESS_TIKA_ENDPOINT: http://paperless-tika:9998 + PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://paperless-gotenberg:3000 + + # Más robusto cuando los ficheros llegan por sync/mount y no por inotify puro + PAPERLESS_CONSUMER_POLLING: ${PAPERLESS_CONSUMER_POLLING} + volumes: + - /opt/paperless/data:/usr/src/paperless/data:Z + - /opt/paperless/media:/usr/src/paperless/media:Z + - /opt/paperless/export:/usr/src/paperless/export:Z + - /opt/paperless/consume:/usr/src/paperless/consume:Z + networks: + - paperless_internal + - proxy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + + - traefik.http.routers.paperless.rule=Host(`${PAPERLESS_DOMAIN}`) + - traefik.http.routers.paperless.entrypoints=websecure + - traefik.http.routers.paperless.tls=true + - traefik.http.routers.paperless.tls.certresolver=${TRAEFIK_CERTRESOLVER} + - traefik.http.routers.paperless.middlewares=paperless-secure-headers + + - traefik.http.middlewares.paperless-secure-headers.headers.stsSeconds=31536000 + - traefik.http.middlewares.paperless-secure-headers.headers.stsIncludeSubdomains=true + - traefik.http.middlewares.paperless-secure-headers.headers.stsPreload=true + - traefik.http.middlewares.paperless-secure-headers.headers.contentTypeNosniff=true + - traefik.http.middlewares.paperless-secure-headers.headers.browserXssFilter=true + + - traefik.http.services.paperless.loadbalancer.server.port=8000 + + paperless-ai: + image: clusterzx/paperless-ai:latest + container_name: paperless-ai + restart: unless-stopped + depends_on: + - paperless + environment: + TZ: ${TZ} + volumes: + - /opt/paperless-ai/data:/app/data:Z + networks: + - paperless_internal + - proxy + labels: + - traefik.enable=true + - traefik.docker.network=proxy + + - traefik.http.routers.paperless-ai.rule=Host(`${PAPERLESS_AI_DOMAIN}`) + - traefik.http.routers.paperless-ai.entrypoints=websecure + - traefik.http.routers.paperless-ai.tls=true + - traefik.http.routers.paperless-ai.tls.certresolver=${TRAEFIK_CERTRESOLVER} + - traefik.http.routers.paperless-ai.middlewares=paperless-ai-secure-headers + + - traefik.http.middlewares.paperless-ai-secure-headers.headers.stsSeconds=31536000 + - traefik.http.middlewares.paperless-ai-secure-headers.headers.stsIncludeSubdomains=true + - traefik.http.middlewares.paperless-ai-secure-headers.headers.stsPreload=true + - traefik.http.middlewares.paperless-ai-secure-headers.headers.contentTypeNosniff=true + + - traefik.http.services.paperless-ai.loadbalancer.server.port=3000 + + # Sync unidireccional: Nextcloud/Paperless-Inbox -> paperless/consume + paperless-inbox-sync: + image: rclone/rclone:latest + container_name: paperless-inbox-sync + restart: unless-stopped + depends_on: + - paperless + entrypoint: + - /bin/sh + - /rclone-sync.sh + environment: + TZ: ${TZ} + + RCLONE_CONFIG_NC_TYPE: webdav + RCLONE_CONFIG_NC_URL: https://${NC_DOMAIN}/remote.php/dav/files/${NC_WEBDAV_USER} + RCLONE_CONFIG_NC_VENDOR: nextcloud + RCLONE_CONFIG_NC_USER: ${NC_WEBDAV_USER} + RCLONE_CONFIG_NC_PASS: ${NC_WEBDAV_PASS} + + RCLONE_SYNC_INTERVAL: ${RCLONE_SYNC_INTERVAL} + PAPERLESS_INBOX_DIR: ${PAPERLESS_INBOX_DIR} + volumes: + - /opt/paperless/consume:/consume:Z + - /opt/rclone:/config/rclone:Z + - /opt/paperless/rclone-sync.sh:/rclone-sync.sh:ro,Z + networks: + - paperless_internal + +networks: + paperless_internal: + driver: bridge + + proxy: + external: true diff --git a/paperless/stack.env b/paperless/stack.env new file mode 100644 index 0000000..4f448dc --- /dev/null +++ b/paperless/stack.env @@ -0,0 +1,19 @@ +TZ=Europe/Madrid +NC_DOMAIN=nextcloud.example.com +PAPERLESS_DOMAIN=paperless.example.com +PAPERLESS_AI_DOMAIN=paperless-ai.example.com +TRAEFIK_CERTRESOLVER=letsencrypt +TRUSTED_PROXIES=10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 +PAPERLESS_DBNAME=paperless +PAPERLESS_DBUSER=paperless +PAPERLESS_DBPASS=change_me_paperless_db_password_long_and_secure +PAPERLESS_SECRET_KEY=change_me_paperless_secret_key_long_and_random_string +PAPERLESS_ADMIN_USER=admin +PAPERLESS_ADMIN_PASSWORD=change_me_paperless_admin_password_long_and_secure +PAPERLESS_ADMIN_MAIL=admin@example.com +PAPERLESS_CONSUMER_POLLING=60 +PAPERLESS_ALLOWED_HOSTS=paperless.example.com,paperless,localhost +NC_WEBDAV_USER=paperless +NC_WEBDAV_PASS=change_me_nextcloud_webdav_password_long_and_random +PAPERLESS_INBOX_DIR=Paperless-Inbox +RCLONE_SYNC_INTERVAL=60