feat: migrate Outline + n8n to main server, rename S3 buckets to walava-*
- Add Outline, outline-db, outline-redis, n8n, outline-mcp containers to main docker-compose - Add env.outline.j2 template with Resend SMTP and S3 (walava-outline bucket) - Update Traefik routes: wiki → outline:3000, auto → n8n:5678 (local, not cross-server) - Rename S3 buckets: visual-backup → walava-backup, visual-outline → walava-outline - Extend backup.sh.j2: add Outline DB, n8n, Plane MinIO to backup scope - Add outline_image, n8n_image, outline_mcp_image to services/defaults - Remove Authelia config deployment tasks from configs.yml - Add outline-internal and n8n-internal networks to docker-compose Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
fba7eb68ea
commit
489791403c
7 changed files with 224 additions and 24 deletions
|
|
@ -5,4 +5,4 @@ backup_user: deploy
|
|||
|
||||
# Timeweb S3 offsite backups
|
||||
s3_endpoint: "https://s3.timeweb.cloud"
|
||||
s3_bucket: "visual-backup"
|
||||
s3_bucket: "walava-backup"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ docker exec plane-db pg_dump -U plane plane \
|
|||
| gzip > "${WORK_DIR}/data/databases/plane.sql.gz"
|
||||
log " → databases/plane.sql.gz ($(du -sh "${WORK_DIR}/data/databases/plane.sql.gz" | cut -f1))"
|
||||
|
||||
# ── PostgreSQL: Outline ──────────────────────────────────────────────────────
|
||||
log "Dumping outline-db..."
|
||||
docker exec outline-db pg_dump -U outline outline \
|
||||
| gzip > "${WORK_DIR}/data/databases/outline.sql.gz"
|
||||
log " → databases/outline.sql.gz ($(du -sh "${WORK_DIR}/data/databases/outline.sql.gz" | cut -f1))"
|
||||
|
||||
# ── Forgejo data volume (repos, attachments, LFS) ───────────────────────────
|
||||
log "Backing up Forgejo data..."
|
||||
docker run --rm \
|
||||
|
|
@ -50,6 +56,24 @@ docker run --rm \
|
|||
tar czf /backup/uptime-kuma.tar.gz /app/data
|
||||
log " → volumes/uptime-kuma.tar.gz ($(du -sh "${WORK_DIR}/data/volumes/uptime-kuma.tar.gz" | cut -f1))"
|
||||
|
||||
# ── n8n workflows + credentials ──────────────────────────────────────────────
|
||||
log "Backing up n8n..."
|
||||
docker run --rm \
|
||||
--volumes-from n8n \
|
||||
-v "${WORK_DIR}/data/volumes:/backup" \
|
||||
alpine:3 \
|
||||
tar czf /backup/n8n.tar.gz /home/node/.n8n
|
||||
log " → volumes/n8n.tar.gz ($(du -sh "${WORK_DIR}/data/volumes/n8n.tar.gz" | cut -f1))"
|
||||
|
||||
# ── Plane MinIO (uploaded files / attachments) ───────────────────────────────
|
||||
log "Backing up Plane MinIO..."
|
||||
docker run --rm \
|
||||
--volumes-from plane-minio \
|
||||
-v "${WORK_DIR}/data/volumes:/backup" \
|
||||
alpine:3 \
|
||||
tar czf /backup/plane-minio.tar.gz /data
|
||||
log " → volumes/plane-minio.tar.gz ($(du -sh "${WORK_DIR}/data/volumes/plane-minio.tar.gz" | cut -f1))"
|
||||
|
||||
# ── Add restore instructions ─────────────────────────────────────────────────
|
||||
cat > "${WORK_DIR}/data/RESTORE.md" << 'RESTORE_EOF'
|
||||
# Restore Instructions
|
||||
|
|
@ -72,6 +96,9 @@ zcat data/databases/forgejo.sql.gz | docker exec -i forgejo-db psql -U forgejo f
|
|||
|
||||
# Plane DB
|
||||
zcat data/databases/plane.sql.gz | docker exec -i plane-db psql -U plane plane
|
||||
|
||||
# Outline DB
|
||||
zcat data/databases/outline.sql.gz | docker exec -i outline-db psql -U outline outline
|
||||
```
|
||||
|
||||
## Step 3 — Restore volume data
|
||||
|
|
@ -80,9 +107,17 @@ zcat data/databases/plane.sql.gz | docker exec -i plane-db psql -U plane plane
|
|||
docker run --rm --volumes-from forgejo -v $(pwd)/data/volumes:/backup \
|
||||
alpine:3 sh -c "cd / && tar xzf /backup/forgejo.tar.gz"
|
||||
|
||||
# Uptime Kuma — extracts /app/data/ into the container
|
||||
# Uptime Kuma
|
||||
docker run --rm --volumes-from uptime-kuma -v $(pwd)/data/volumes:/backup \
|
||||
alpine:3 sh -c "cd / && tar xzf /backup/uptime-kuma.tar.gz"
|
||||
|
||||
# n8n
|
||||
docker run --rm --volumes-from n8n -v $(pwd)/data/volumes:/backup \
|
||||
alpine:3 sh -c "cd / && tar xzf /backup/n8n.tar.gz"
|
||||
|
||||
# Plane MinIO (uploaded files)
|
||||
docker run --rm --volumes-from plane-minio -v $(pwd)/data/volumes:/backup \
|
||||
alpine:3 sh -c "cd / && tar xzf /backup/plane-minio.tar.gz"
|
||||
```
|
||||
|
||||
## Step 4 — Restart services
|
||||
|
|
|
|||
|
|
@ -28,3 +28,8 @@ promtail_image: "grafana/promtail:3.4.3" # https://hub
|
|||
crowdsec_image: "crowdsecurity/crowdsec:v1.6.8" # https://hub.docker.com/r/crowdsecurity/crowdsec/tags
|
||||
redis_image: "redis:7-alpine"
|
||||
uptime_kuma_image: "louislam/uptime-kuma:1" # https://hub.docker.com/r/louislam/uptime-kuma/tags
|
||||
outline_image: "outlinewiki/outline:0.80.2" # https://hub.docker.com/r/outlinewiki/outline/tags
|
||||
outline_db_image: "postgres:15-alpine"
|
||||
outline_redis_image: "redis:7-alpine"
|
||||
n8n_image: "n8nio/n8n:1.89.2" # https://hub.docker.com/r/n8nio/n8n/tags
|
||||
outline_mcp_image: "git.{{ domain_base }}/jack/outline-mcp:latest"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@
|
|||
mode: "0600"
|
||||
notify: Restart stack
|
||||
|
||||
- name: Deploy Outline .env file
|
||||
ansible.builtin.template:
|
||||
src: env.outline.j2
|
||||
dest: "{{ services_root }}/.env.outline"
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_group }}"
|
||||
mode: "0600"
|
||||
notify: Restart stack
|
||||
|
||||
- name: Deploy docker-compose.yml
|
||||
ansible.builtin.template:
|
||||
src: docker-compose.yml.j2
|
||||
|
|
@ -143,24 +152,6 @@
|
|||
mode: "0644"
|
||||
notify: Restart stack
|
||||
|
||||
- name: Deploy Authelia configuration
|
||||
ansible.builtin.template:
|
||||
src: authelia/configuration.yml.j2
|
||||
dest: "{{ services_root }}/authelia/configuration.yml"
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_group }}"
|
||||
mode: "0600"
|
||||
notify: Restart stack
|
||||
|
||||
- name: Deploy Authelia users database
|
||||
ansible.builtin.template:
|
||||
src: authelia/users.yml.j2
|
||||
dest: "{{ services_root }}/authelia/users.yml"
|
||||
owner: "{{ deploy_user }}"
|
||||
group: "{{ deploy_group }}"
|
||||
mode: "0600"
|
||||
notify: Restart stack
|
||||
|
||||
- name: Deploy Traefik logrotate config
|
||||
ansible.builtin.template:
|
||||
src: logrotate/traefik.j2
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ networks:
|
|||
monitoring:
|
||||
driver: bridge
|
||||
internal: true
|
||||
outline-internal:
|
||||
driver: bridge
|
||||
internal: true
|
||||
n8n-internal:
|
||||
driver: bridge
|
||||
internal: true
|
||||
volumes:
|
||||
forgejo_data:
|
||||
forgejo_db_data:
|
||||
|
|
@ -39,6 +45,9 @@ volumes:
|
|||
loki_data:
|
||||
crowdsec_data:
|
||||
uptime_kuma_data:
|
||||
outline_db_data:
|
||||
outline_redis_data:
|
||||
n8n_data:
|
||||
|
||||
services:
|
||||
|
||||
|
|
@ -595,3 +604,123 @@ services:
|
|||
options:
|
||||
max-size: "5m"
|
||||
max-file: "2"
|
||||
|
||||
# ── Outline wiki ────────────────────────────────────────────────────────────
|
||||
outline:
|
||||
image: {{ outline_image }}
|
||||
container_name: outline
|
||||
restart: unless-stopped
|
||||
env_file: .env.outline
|
||||
networks:
|
||||
- outline-internal
|
||||
- backend
|
||||
depends_on:
|
||||
outline-db:
|
||||
condition: service_healthy
|
||||
outline-redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/_health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
outline-db:
|
||||
image: {{ outline_db_image }}
|
||||
container_name: outline-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: outline
|
||||
POSTGRES_USER: outline
|
||||
POSTGRES_PASSWORD: {{ outline_db_password }}
|
||||
networks:
|
||||
- outline-internal
|
||||
volumes:
|
||||
- outline_db_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U outline"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
outline-redis:
|
||||
image: {{ outline_redis_image }}
|
||||
container_name: outline-redis
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- outline-internal
|
||||
volumes:
|
||||
- outline_redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# ── n8n workflow automation ──────────────────────────────────────────────────
|
||||
n8n:
|
||||
image: {{ n8n_image }}
|
||||
container_name: n8n
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- n8n-internal
|
||||
- backend
|
||||
volumes:
|
||||
- n8n_data:/home/node/.n8n
|
||||
environment:
|
||||
- N8N_HOST={{ domain_n8n }}
|
||||
- N8N_PORT=5678
|
||||
- N8N_PROTOCOL=https
|
||||
- WEBHOOK_URL=https://{{ domain_n8n }}/
|
||||
- N8N_ENCRYPTION_KEY={{ n8n_encryption_key }}
|
||||
- N8N_USER_MANAGEMENT_JWT_SECRET={{ n8n_jwt_secret }}
|
||||
- GENERIC_TIMEZONE=Europe/Moscow
|
||||
- TZ=Europe/Moscow
|
||||
- N8N_METRICS=false
|
||||
- N8N_LOG_LEVEL=warn
|
||||
- EXECUTIONS_DATA_PRUNE=true
|
||||
- EXECUTIONS_DATA_MAX_AGE=336
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5678/healthz"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# ── Outline MCP server ───────────────────────────────────────────────────────
|
||||
outline-mcp:
|
||||
image: {{ outline_mcp_image }}
|
||||
container_name: outline-mcp
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- backend
|
||||
environment:
|
||||
- OUTLINE_URL=https://{{ domain_wiki }}
|
||||
- OUTLINE_API_KEY={{ outline_mcp_api_key }}
|
||||
- PORT=8765
|
||||
- HOST=0.0.0.0
|
||||
- LOG_LEVEL=INFO
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
|
|
|||
42
roles/services/templates/env.outline.j2
Normal file
42
roles/services/templates/env.outline.j2
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Outline env — generated by Ansible
|
||||
NODE_ENV=production
|
||||
SECRET_KEY={{ outline_secret_key }}
|
||||
UTILS_SECRET={{ outline_utils_secret }}
|
||||
|
||||
# Database
|
||||
DATABASE_URL=postgres://outline:{{ outline_db_password }}@outline-db:5432/outline
|
||||
PGSSLMODE=disable
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://outline-redis:6379
|
||||
|
||||
# App URL
|
||||
URL=https://{{ domain_wiki }}
|
||||
PORT=3000
|
||||
|
||||
# S3 file storage (Timeweb Object Storage)
|
||||
AWS_ACCESS_KEY_ID={{ s3_access_key }}
|
||||
AWS_SECRET_ACCESS_KEY={{ s3_secret_key }}
|
||||
AWS_REGION=ru-1
|
||||
AWS_S3_UPLOAD_BUCKET_NAME=walava-outline
|
||||
AWS_S3_UPLOAD_BUCKET_URL=https://s3.timeweb.cloud
|
||||
AWS_S3_FORCE_PATH_STYLE=true
|
||||
AWS_S3_ACL=private
|
||||
FILE_STORAGE=s3
|
||||
|
||||
# Auth
|
||||
AUTH_PROVIDERS=email
|
||||
|
||||
# SMTP via Resend (direct — main server has outbound SMTP)
|
||||
SMTP_HOST=smtp.resend.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USERNAME=resend
|
||||
SMTP_PASSWORD={{ resend_api_key }}
|
||||
SMTP_FROM_EMAIL=noreply@{{ domain_base }}
|
||||
SMTP_FROM_NAME=Visual Wiki
|
||||
SMTP_SECURE=false
|
||||
|
||||
# Optional
|
||||
DEFAULT_LANGUAGE=en_US
|
||||
RATE_LIMITER_ENABLED=true
|
||||
ENABLE_UPDATES=false
|
||||
|
|
@ -89,7 +89,6 @@ http:
|
|||
service: walava-landing
|
||||
middlewares: [rate-limit-default]
|
||||
|
||||
# ── Cross-server: tools ({{ ip_tools }}) ─────────────────────────────────
|
||||
wiki:
|
||||
rule: "Host(`{{ domain_wiki }}`)"
|
||||
entrypoints: [websecure]
|
||||
|
|
@ -147,16 +146,15 @@ http:
|
|||
servers:
|
||||
- url: "http://walava-web:80"
|
||||
|
||||
# ── Cross-server services ─────────────────────────────────────────────────
|
||||
wiki:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://{{ ip_tools }}:3000"
|
||||
- url: "http://outline:3000"
|
||||
|
||||
n8n:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://{{ ip_tools }}:5678"
|
||||
- url: "http://n8n:5678"
|
||||
|
||||
middlewares:
|
||||
# ── Security Headers (applied globally via entrypoint) ─────────────────
|
||||
|
|
|
|||
Loading…
Reference in a new issue