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
|
# Timeweb S3 offsite backups
|
||||||
s3_endpoint: "https://s3.timeweb.cloud"
|
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"
|
| gzip > "${WORK_DIR}/data/databases/plane.sql.gz"
|
||||||
log " → databases/plane.sql.gz ($(du -sh "${WORK_DIR}/data/databases/plane.sql.gz" | cut -f1))"
|
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) ───────────────────────────
|
# ── Forgejo data volume (repos, attachments, LFS) ───────────────────────────
|
||||||
log "Backing up Forgejo data..."
|
log "Backing up Forgejo data..."
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
|
|
@ -50,6 +56,24 @@ docker run --rm \
|
||||||
tar czf /backup/uptime-kuma.tar.gz /app/data
|
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))"
|
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 ─────────────────────────────────────────────────
|
# ── Add restore instructions ─────────────────────────────────────────────────
|
||||||
cat > "${WORK_DIR}/data/RESTORE.md" << 'RESTORE_EOF'
|
cat > "${WORK_DIR}/data/RESTORE.md" << 'RESTORE_EOF'
|
||||||
# Restore Instructions
|
# Restore Instructions
|
||||||
|
|
@ -72,6 +96,9 @@ zcat data/databases/forgejo.sql.gz | docker exec -i forgejo-db psql -U forgejo f
|
||||||
|
|
||||||
# Plane DB
|
# Plane DB
|
||||||
zcat data/databases/plane.sql.gz | docker exec -i plane-db psql -U plane plane
|
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
|
## 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 \
|
docker run --rm --volumes-from forgejo -v $(pwd)/data/volumes:/backup \
|
||||||
alpine:3 sh -c "cd / && tar xzf /backup/forgejo.tar.gz"
|
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 \
|
docker run --rm --volumes-from uptime-kuma -v $(pwd)/data/volumes:/backup \
|
||||||
alpine:3 sh -c "cd / && tar xzf /backup/uptime-kuma.tar.gz"
|
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
|
## 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
|
crowdsec_image: "crowdsecurity/crowdsec:v1.6.8" # https://hub.docker.com/r/crowdsecurity/crowdsec/tags
|
||||||
redis_image: "redis:7-alpine"
|
redis_image: "redis:7-alpine"
|
||||||
uptime_kuma_image: "louislam/uptime-kuma:1" # https://hub.docker.com/r/louislam/uptime-kuma/tags
|
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"
|
mode: "0600"
|
||||||
notify: Restart stack
|
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
|
- name: Deploy docker-compose.yml
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: docker-compose.yml.j2
|
src: docker-compose.yml.j2
|
||||||
|
|
@ -143,24 +152,6 @@
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
notify: Restart stack
|
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
|
- name: Deploy Traefik logrotate config
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: logrotate/traefik.j2
|
src: logrotate/traefik.j2
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ networks:
|
||||||
monitoring:
|
monitoring:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
internal: true
|
internal: true
|
||||||
|
outline-internal:
|
||||||
|
driver: bridge
|
||||||
|
internal: true
|
||||||
|
n8n-internal:
|
||||||
|
driver: bridge
|
||||||
|
internal: true
|
||||||
volumes:
|
volumes:
|
||||||
forgejo_data:
|
forgejo_data:
|
||||||
forgejo_db_data:
|
forgejo_db_data:
|
||||||
|
|
@ -39,6 +45,9 @@ volumes:
|
||||||
loki_data:
|
loki_data:
|
||||||
crowdsec_data:
|
crowdsec_data:
|
||||||
uptime_kuma_data:
|
uptime_kuma_data:
|
||||||
|
outline_db_data:
|
||||||
|
outline_redis_data:
|
||||||
|
n8n_data:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
|
|
@ -595,3 +604,123 @@ services:
|
||||||
options:
|
options:
|
||||||
max-size: "5m"
|
max-size: "5m"
|
||||||
max-file: "2"
|
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
|
service: walava-landing
|
||||||
middlewares: [rate-limit-default]
|
middlewares: [rate-limit-default]
|
||||||
|
|
||||||
# ── Cross-server: tools ({{ ip_tools }}) ─────────────────────────────────
|
|
||||||
wiki:
|
wiki:
|
||||||
rule: "Host(`{{ domain_wiki }}`)"
|
rule: "Host(`{{ domain_wiki }}`)"
|
||||||
entrypoints: [websecure]
|
entrypoints: [websecure]
|
||||||
|
|
@ -147,16 +146,15 @@ http:
|
||||||
servers:
|
servers:
|
||||||
- url: "http://walava-web:80"
|
- url: "http://walava-web:80"
|
||||||
|
|
||||||
# ── Cross-server services ─────────────────────────────────────────────────
|
|
||||||
wiki:
|
wiki:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
servers:
|
servers:
|
||||||
- url: "http://{{ ip_tools }}:3000"
|
- url: "http://outline:3000"
|
||||||
|
|
||||||
n8n:
|
n8n:
|
||||||
loadBalancer:
|
loadBalancer:
|
||||||
servers:
|
servers:
|
||||||
- url: "http://{{ ip_tools }}:5678"
|
- url: "http://n8n:5678"
|
||||||
|
|
||||||
middlewares:
|
middlewares:
|
||||||
# ── Security Headers (applied globally via entrypoint) ─────────────────
|
# ── Security Headers (applied globally via entrypoint) ─────────────────
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue