feat(ai): update n8n and paperless model stack

This commit is contained in:
Eduardo David Paredes Vara
2026-07-25 11:21:57 +00:00
parent 393a716d57
commit aaf50e5af7
6 changed files with 155 additions and 59 deletions
+8 -11
View File
@@ -19,17 +19,14 @@ Este stack despliega n8n con:
2. **Registro DNS**: Configura el registro A para tu dominio n8n
3. **Clave de cifrado**: Genera una clave segura para cifrar credenciales
### Desde Portainer
### Desde Docker Compose
1. Ve a **Stacks** → **Add stack**
2. Nombre: `n8n`
3. Selecciona **Repository** o **Git repository**
4. Configura:
- Repository URL: `<tu-repositorio>`
- Repository reference: `main`
- Compose path: `n8n/docker-compose.yml`
5. Copia `n8n/stack.env` a `n8n/.env` y carga `n8n/.env` como archivo de variables de entorno
6. Haz clic en **Deploy the stack**
Asegurate de tener `n8n/.env` configurado y despliega:
```bash
cd n8n
docker compose --env-file .env up -d
```
### Variables de Entorno Importantes
@@ -334,7 +331,7 @@ También puedes exportar workflows manualmente:
```env
N8N_IMAGE=n8nio/n8n:latest
```
3. Actualiza el stack en Portainer
3. Redespiega con Docker Compose
4. Verifica los logs: `docker logs n8n`
5. Prueba algunos workflows críticos
+92
View File
@@ -0,0 +1,92 @@
# n8n upgrade to 2.30.5
Prepared: 2026-07-15T10:28Z
## Current state
- Current running version before upgrade: `2.22.5`
- Target version: `2.30.5`
- Target image pulled locally: `n8nio/n8n:2.30.5`
- Target image digest: `sha256:450853cd21a2ce36587c4c860eb26927c1ceba9496bf55f4c213b5d3a6dc8c6f`
- Previous image digest: `sha256:a49bc161141d6c4b9c495b5a6e3c7c1932e61d2ed2fe3fdca01262064b4b23ca`
## Backup
Backup directory:
```bash
/opt/backups/n8n-upgrade-20260715T102759Z
```
Contents:
- `n8n-postgres.dump`
- `n8n-data.tgz`
- `SHA256SUMS`
Verify backup:
```bash
sudo sha256sum -c /opt/backups/n8n-upgrade-20260715T102759Z/SHA256SUMS
sudo cat /opt/backups/n8n-upgrade-20260715T102759Z/n8n-postgres.dump | docker exec -i n8n-pg pg_restore -l | head
sudo tar -tzf /opt/backups/n8n-upgrade-20260715T102759Z/n8n-data.tgz | head
```
## Upgrade
```bash
cd /home/felidae/Portainer_repo/n8n
docker compose --env-file .env up -d n8n
```
## Verification
```bash
docker exec n8n n8n --version
docker ps --filter name=n8n --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
health-results
docker logs --since 10m n8n
```
Expected:
- `docker exec n8n n8n --version` prints `2.30.5`
- `health-results` reports `11/11 up`
- No recurring `ERR_ERL_UNEXPECTED_X_FORWARDED_FOR`
## Rollback
If the container fails to start or workflows fail after migration:
1. Stop n8n:
```bash
docker compose --env-file .env stop n8n
```
2. Restore the previous image in `docker-compose.yml`:
```yaml
image: n8nio/n8n@sha256:a49bc161141d6c4b9c495b5a6e3c7c1932e61d2ed2fe3fdca01262064b4b23ca
```
3. If DB migrations need rollback, restore Postgres from backup. This is destructive to current n8n DB state:
```bash
docker compose --env-file .env stop n8n
docker exec -i n8n-pg dropdb -U n8n n8n
docker exec -i n8n-pg createdb -U n8n n8n
sudo cat /opt/backups/n8n-upgrade-20260715T102759Z/n8n-postgres.dump | docker exec -i n8n-pg pg_restore -U n8n -d n8n --clean --if-exists
```
4. Restore `/opt/n8n/data` only if needed:
```bash
sudo tar -C /opt/n8n -xzf /opt/backups/n8n-upgrade-20260715T102759Z/n8n-data.tgz
```
5. Start old n8n:
```bash
docker compose --env-file .env up -d n8n
```
+2 -3
View File
@@ -1,7 +1,6 @@
services:
n8n:
image: n8nio/n8n:latest
pull_policy: always
image: n8nio/n8n:2.30.5
container_name: n8n
restart: unless-stopped
environment:
@@ -16,6 +15,7 @@ services:
N8N_PORT: ${N8N_PORT}
N8N_PROTOCOL: ${N8N_PROTOCOL}
WEBHOOK_URL: ${N8N_WEBHOOK_URL}
N8N_PROXY_HOPS: ${N8N_PROXY_HOPS}
GENERIC_TIMEZONE: ${N8N_TIMEZONE}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
@@ -59,7 +59,6 @@ services:
n8n-db:
image: postgres:16
pull_policy: always
container_name: n8n-pg
restart: unless-stopped
environment:
+1
View File
@@ -11,6 +11,7 @@ N8N_HOST=
N8N_PORT=5678
N8N_PROTOCOL=https
N8N_WEBHOOK_URL=https://app.example.com
N8N_PROXY_HOPS=1
N8N_TIMEZONE=Europe/Madrid
+3 -8
View File
@@ -1,7 +1,6 @@
services:
openwebui:
image: ghcr.io/open-webui/open-webui:${OPENWEBUI_VERSION}
pull_policy: always
image: ghcr.io/open-webui/open-webui@sha256:9fcea9c6e32ab60b0498f3986c6cdf651ddbe61db48d2213a3d28048ddd673d4
container_name: openwebui
restart: unless-stopped
environment:
@@ -16,19 +15,15 @@ services:
ENABLE_LOGIN_FORM: ${ENABLE_LOGIN_FORM}
WEBUI_AUTH_TRUSTED_EMAIL_HEADER: ${WEBUI_AUTH_TRUSTED_EMAIL_HEADER}
WEBUI_AUTH_TRUSTED_NAME_HEADER: ${WEBUI_AUTH_TRUSTED_NAME_HEADER}
DEFAULT_USER_ROLE: ${DEFAULT_USER_ROLE:-user}
volumes:
- ${OPENWEBUI_DATA_PATH}:/app/backend/data:Z
networks:
- proxy
labels:
prune.protect: "true"
traefik.enable: "true"
traefik.docker.network: "${TRAEFIK_DOCKER_NETWORK}"
traefik.http.routers.openwebui.rule: "Host(`${OPENWEBUI_DOMAIN}`)"
traefik.http.routers.openwebui.entrypoints: "${TRAEFIK_ENTRYPOINT_SECURE}"
traefik.http.routers.openwebui.tls: "true"
traefik.http.routers.openwebui.tls.certresolver: "${TRAEFIK_CERTRESOLVER}"
traefik.http.routers.openwebui.middlewares: "crowdsec-bouncer@file,${TRAEFIK_AUTH_MIDDLEWARE}"
traefik.http.services.openwebui.loadbalancer.server.port: "8080"
homepage.group: "IA"
homepage.name: "Open WebUI"
homepage.icon: "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/open-webui.svg"
+49 -37
View File
@@ -3,6 +3,8 @@ services:
image: postgres:18
container_name: paperless-db
restart: unless-stopped
labels:
prune.protect: "true"
environment:
TZ: ${TZ}
POSTGRES_DB: ${PAPERLESS_DBNAME}
@@ -12,44 +14,73 @@ services:
- /opt/paperless/pgdata:/var/lib/postgresql:Z
networks:
- paperless_internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${PAPERLESS_DBUSER} -d ${PAPERLESS_DBNAME}"]
interval: 5s
timeout: 5s
retries: 10
paperless-redis:
image: redis:8
container_name: paperless-redis
restart: unless-stopped
labels:
prune.protect: "true"
volumes:
- /opt/paperless/redis:/data:Z
networks:
- paperless_internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 10
paperless-gotenberg:
image: gotenberg/gotenberg:8.27
container_name: paperless-gotenberg
restart: unless-stopped
labels:
prune.protect: "true"
command:
- "gotenberg"
- "--chromium-disable-javascript=true"
- "--chromium-allow-list=file:///tmp/.*"
networks:
- paperless_internal
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 5s
timeout: 5s
retries: 10
paperless-tika:
image: apache/tika:latest
image: apache/tika@sha256:c0154cb95587cde64be74f35ada1a2bd7892219f3f0ac3c9dc6cab34046b3573
container_name: paperless-tika
restart: unless-stopped
labels:
prune.protect: "true"
networks:
- paperless_internal
healthcheck:
test: ["CMD-SHELL", "bash -c 'exec 3<>/dev/tcp/localhost/9998'"]
interval: 5s
timeout: 5s
retries: 10
paperless:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
image: ghcr.io/paperless-ngx/paperless-ngx@sha256:6c86cad803970ea782683a8e80e7403444c5bf3cf70de63b4d3c8e87500db92f
container_name: paperless
pull_policy: always
restart: unless-stopped
depends_on:
- paperless-db
- paperless-redis
- paperless-gotenberg
- paperless-tika
paperless-db:
condition: service_healthy
paperless-redis:
condition: service_healthy
paperless-gotenberg:
condition: service_healthy
paperless-tika:
condition: service_healthy
environment:
TZ: ${TZ}
@@ -94,53 +125,31 @@ services:
- proxy
- mail_internal
labels:
- traefik.enable=true
- traefik.docker.network=proxy
prune.protect: "true"
- 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
image: admonstrator/paperless-ai-next:v2026.07.03
container_name: paperless-ai
pull_policy: always
restart: unless-stopped
depends_on:
- paperless
paperless:
condition: service_healthy
environment:
TZ: ${TZ}
TRUST_PROXY: "true"
volumes:
- /opt/paperless-ai/data:/app/data:Z
networks:
- paperless_internal
- proxy
labels:
- traefik.enable=true
- traefik.docker.network=proxy
- prune.protect=true
- 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
- homepage.group=Productividad
- homepage.name=Paperless AI
- homepage.icon=https://media.sys.truenas.net/apps/paperless-ai/icons/icon.png
@@ -150,11 +159,14 @@ services:
# Sync unidireccional: Nextcloud/Paperless-Inbox -> paperless/consume
paperless-inbox-sync:
image: rclone/rclone:latest
image: rclone/rclone@sha256:8a17d9b5cd5ce71bbb42e49e92ee83575d7fb03f6233d949d328e9d029b9376d
container_name: paperless-inbox-sync
restart: unless-stopped
labels:
prune.protect: "true"
depends_on:
- paperless
paperless:
condition: service_healthy
entrypoint:
- /bin/sh
- /rclone-sync.sh