Skip to main content
< All Topics
Print

Chapter 5: Infrastructure Upgrades

Chapter 5: Infrastructure Upgrades

Last Updated: 2026-03

## 5.1 Upgrade Philosophy

Every upgrade follows the same pattern:

1. Backup — verify non-zero backup files exist.

2. Baseline — capture current stats and test results.

3. Upgrade — pull new images, restart services.

4. Verify — run smoke tests and integration tests.

5. Rollback — if verification fails, restore from backup.

Never skip any step. Never upgrade during active workflow execution.

5.2 Pre-Upgrade Checklist

Run this checklist before every upgrade, regardless of scope:


cd ITI/infrastructure/n8n-dify

# 1. Run backup
bash backup.sh

# 2. Verify backup files are non-zero
ls -lh /Users/username/Cursor/Archives/ | grep $(date +%Y%m%d)

# 3. Capture resource baseline
docker stats --no-stream > /Users/username/Cursor/Archives/docker-stats-pre-upgrade-$(date +%Y%m%d).log

# 4. Run smoke tests
cd tests
python -m pytest test_docker_health.py test_n8n_webhooks.py -m smoke -v

# 5. Record current image versions
cd ..
docker compose images

# 6. Check that no critical workflows are currently executing
# Open http://localhost:5678 > Executions > verify no active runs

All 6 steps must complete without errors. If any step fails, do not proceed with the upgrade.


5.3 Routine Image Updates (Monthly)

Most images use :latest or minor-version tags. A monthly pull keeps them current:


cd ITI/infrastructure/n8n-dify
docker compose pull
docker compose up -d

Then run the post-upgrade verification (Section 5.7).


5.4 Upgrading n8n

n8n uses n8nio/n8n:latest. A docker compose pull upgrades it automatically.

Special considerations

Encryption key: N8N_ENCRYPTION_KEY in .env must never change. It encrypts all stored credentials. There is no migration path if this key is changed — all credentials become permanently unrecoverable.

DB migrations: n8n runs internal database migrations on startup. After an upgrade, watch the logs:


docker compose logs -f iti-n8n | head -50

Look for migration completion messages before using the UI.

Workflow activation: Major n8n version upgrades may deactivate workflows. After upgrading:


# Count active workflows via API
curl -s http://localhost:5678/api/v1/workflows?active=true \
  -H "X-N8N-API-KEY: <your-api-key>" | python3 -m json.tool | grep '"id"' | wc -l

Compare this count to the pre-upgrade baseline. If workflows were deactivated, re-publish each one through the n8n UI or API.


5.5 Upgrading Dify

Dify runs three coordinated images: dify-api, dify-worker, and dify-web. These must always be the same version.

Pinned vs latest images

Image Strategy Notes
dify-api :latest in development May pin in production
dify-worker Same as dify-api Must match exactly
dify-web Same as dify-api Must match exactly
dify-sandbox Pinned (0.2.14) Do not update without release note review
dify-plugin-daemon Pinned (0.5.3-local) Do not update without release note review

Upgrade procedure


# 1. Check Dify release notes at https://github.com/langgenius/dify/releases
# 2. Update pinned tags in docker-compose.yml if necessary
# 3. Pull and restart
docker compose pull iti-dify-api iti-dify-worker iti-dify-web
docker compose up -d

# 4. Verify Dify console loads
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000

# 5. Verify API proxy
curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/console/api/setup

# 6. Test KB retrieval
# Open Dify UI > Knowledge > Retrieval Testing

5.6 Upgrading PostgreSQL (Major Version)

This is the highest-risk upgrade. Perform it only when explicitly needed. Major version upgrades (e.g., pg16 → pg17) require a full dump-and-restore because PostgreSQL data formats are not forward-compatible.

Procedure


cd ITI/infrastructure/n8n-dify

# Step 1: Full backup of all three databases
docker exec iti-postgres pg_dump -U postgres n8n > /Users/username/Cursor/Archives/n8n-db-pre-pgupgrade.sql
docker exec iti-postgres pg_dump -U postgres dify > /Users/username/Cursor/Archives/dify-db-pre-pgupgrade.sql
docker exec iti-postgres pg_dump -U postgres dify_plugin > /Users/username/Cursor/Archives/dify-plugin-db-pre-pgupgrade.sql

# Step 2: Stop the stack
docker compose down

# Step 3: Update the image in docker-compose.yml
# Change: pgvector/pgvector:pg16
# To:     pgvector/pgvector:pg17

# Step 4: Remove the old data volume
docker volume rm n8n-dify_postgres_data

# Step 5: Start only Postgres (let it initialize)
docker compose up -d iti-postgres
# Wait for healthy status
docker compose ps iti-postgres

# Step 6: Restore all databases
docker exec -i iti-postgres psql -U postgres < /Users/username/Cursor/Archives/n8n-db-pre-pgupgrade.sql
docker exec -i iti-postgres psql -U postgres < /Users/username/Cursor/Archives/dify-db-pre-pgupgrade.sql
docker exec -i iti-postgres psql -U postgres < /Users/username/Cursor/Archives/dify-plugin-db-pre-pgupgrade.sql

# Step 7: Verify pgvector extension
docker exec iti-postgres psql -U postgres -d dify -c \
  "SELECT extversion FROM pg_extension WHERE extname='vector';"

# Step 8: Bring up full stack
docker compose up -d

# Step 9: Run full test suite
cd tests
python -m pytest -v

5.7 Post-Upgrade Verification (Mandatory)

Run after every upgrade before considering it complete:


cd ITI/infrastructure/n8n-dify

# 1. All containers healthy
docker compose ps

# 2. Smoke tests
cd tests
python -m pytest test_docker_health.py test_n8n_webhooks.py -m smoke -v

# 3. Integration tests
python -m pytest test_n8n_workflows.py test_postgres_pgvector.py -v

# 4. Verify n8n workflow count matches pre-upgrade
# 5. Verify Dify KBs accessible (Dify UI > Knowledge)
# 6. Check n8n Executions for new errors post-upgrade
# 7. Compare docker stats to pre-upgrade baseline
docker stats --no-stream

5.8 Rollback Procedures

Rollback a single service


# 1. Stop the service
docker compose stop iti-n8n

# 2. Edit docker-compose.yml to pin the previous image version
# Change: n8nio/n8n:latest
# To:     n8nio/n8n:1.XX.X  (the version from pre-upgrade docker compose images output)

# 3. Restart
docker compose up -d iti-n8n

Full stack rollback


# 1. Stop everything
docker compose down

# 2. Restore databases from pre-upgrade backups
docker exec -i iti-postgres psql -U postgres -d n8n < /Users/username/Cursor/Archives/n8n-db-YYYYMMDD.sql
docker exec -i iti-postgres psql -U postgres -d dify < /Users/username/Cursor/Archives/dify-db-YYYYMMDD.sql

# 3. Revert image tags in docker-compose.yml to previous versions

# 4. Restart
docker compose up -d

5.9 Version Pinning Strategy

Image Strategy Reason
pgvector/pgvector:pg16 Pinned to major Major version breaks require dump/restore
redis:7-alpine Pinned to major Redis AOF compatibility
dify-sandbox:0.2.14 Pinned exactly API surface changes with versions
dify-plugin-daemon:0.5.3-local Pinned exactly Plugin compatibility
n8nio/n8n:latest Latest (dev) / pinned (prod) Active development; migrations handle upgrades
langgenius/dify-api:latest Latest (dev) / pinned (prod) Same; Dify handles migrations

Tip: After each upgrade, record the specific image versions from docker compose images in a comment block at the top of docker-compose.yml. This makes rollback much faster.


Previous: Chapter 4 — Daily Operations | Next: Chapter 6 — PostgreSQL & pgvector

Table of Contents