====== 🚀 DV IT Infrastructure Platform - 生产环境部署指南 ======
**更新日期**: 2025年1月
**项目**: DV IT Infrastructure Platform
**部署方式**: 生产环境实际部署
**域名**: oasisvape.co.nz + 二级域名
-----
===== 🎯 部署概述 =====
==== 生产环境信息 ====
* **VPS IP**: 156.67.214.225
* **操作系统**: Ubuntu (Linux 6.11.0-29-generic)
* **Docker Compose**: v2 (docker compose)
* **时区**: Pacific/Auckland
* **部署路径**: /opt/discountvapor-it/
==== 核心原则 ====
* **容器化部署**: 所有服务使用Docker Compose部署
* **自动化SSL**: 通过Traefik自动管理Let's Encrypt证书
* **网络安全**: 仅开放必要端口,通过反向代理访问
* **监控集成**: 完整的监控栈 (cAdvisor + Prometheus + Grafana)
-----
===== 📋 服务版本清单 =====
==== 核心服务 ====
^ 服务 ^ 版本 ^ 官方文档 ^ 访问地址 ^
| ERPNext | v15.67.5 | [[https://github.com/frappe/frappe_docker|Frappe Docker]] | https://erp.oasisvape.co.nz |
| Strapi CMS | 自定义镜像 | [[https://docs.strapi.io/cms/installation/docker|Strapi Docker]] | https://cms.oasisvape.co.nz |
| n8n | v1.100.1 | [[https://docs.n8n.io/hosting/installation/docker|n8n Docker]] | https://n8n.oasisvape.co.nz |
| DokuWiki | 最新版 | [[https://www.dokuwiki.org/docker|DokuWiki Docker]] | https://wiki.oasisvape.co.nz |
| Traefik | v2.10 | [[https://doc.traefik.io/traefik/|Traefik Docs]] | https://traefik.oasisvape.co.nz |
| Grafana | 最新版 | [[https://grafana.com/docs/|Grafana Docs]] | https://grafana.oasisvape.co.nz |
==== 数据库服务 ====
^ 服务 ^ 版本 ^ 用途 ^ 架构 ^
| MariaDB | 10.6 | ERPNext专用数据库 | 独立实例 |
| PostgreSQL | 15-alpine | Strapi + n8n共享数据库 | 共享实例,Schema隔离 |
-----
===== 🏗️ 生产环境部署 =====
==== 1. 环境准备 ====
# 创建项目目录
mkdir -p /opt/discountvapor-it
cd /opt/discountvapor-it
# 创建必要目录
mkdir -p data logs traefik config_backup scripts wiki
==== 2. 网络配置 ====
# 创建Traefik网络
docker network create traefik-network
# 创建Strapi网络
docker network create strapi_network
# 创建ERPNext网络
docker network create discountvapor-it_erpnext-network
# 创建监控网络
docker network create monitoring
==== 3. 环境变量配置 ====
# .env 文件
ERPNEXT_VERSION=v15.67.5
DB_PASSWORD=35@Riccarton
LETSENCRYPT_EMAIL=discountvapor2025@gmail.com
SITES=erp.oasisvape.co.nz
-----
===== 🐳 服务部署配置 =====
==== 1. Traefik 反向代理 ====
# docker-compose-traefik.yml
version: '3.8'
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- traefik_certs:/letsencrypt
networks:
- traefik-network
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`traefik.oasisvape.co.nz`)
- traefik.http.routers.traefik.entrypoints=websecure
- traefik.http.routers.traefik.tls.certresolver=letsencrypt
- traefik.http.services.traefik.loadbalancer.server.port=8080
volumes:
traefik_certs:
driver: local
networks:
traefik-network:
==== 2. Traefik 配置文件 ====
# traefik/traefik.yml
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik-network
certificatesResolvers:
letsencrypt:
acme:
email: admin@discountvapor.co.nz
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
log:
level: INFO
==== 3. ERPNext 部署 ====
# docker-compose-erpnext.yml
version: '3.8'
services:
database:
image: mariadb:10.6
restart: unless-stopped
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --skip-character-set-client-handshake
- --skip-innodb-read-only-compressed
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/mysql
networks:
- erpnext-network
healthcheck:
test: mysqladmin ping -h localhost --password=${DB_PASSWORD}
interval: 1s
retries: 15
redis-cache:
image: redis:6.2-alpine
restart: unless-stopped
volumes:
- redis-cache-data:/data
networks:
- erpnext-network
redis-queue:
image: redis:6.2-alpine
restart: unless-stopped
volumes:
- redis-queue-data:/data
networks:
- erpnext-network
configurator:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: "no"
entrypoint:
- bash
- -c
command:
- >
ls -1 apps > sites/apps.txt;
bench set-config -g db_host database;
bench set-config -gp db_port 3306;
bench set-config -g redis_cache "redis://redis-cache:6379";
bench set-config -g redis_queue "redis://redis-queue:6379";
bench set-config -g redis_socketio "redis://redis-queue:6379";
bench set-config -gp socketio_port 9000;
depends_on:
database:
condition: service_healthy
redis-cache:
condition: service_started
redis-queue:
condition: service_started
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
backend:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
depends_on:
configurator:
condition: service_completed_successfully
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
frontend:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
command:
- nginx-entrypoint.sh
environment:
BACKEND: backend:8000
FRAPPE_SITE_NAME_HEADER: ${SITES}
SOCKETIO: websocket:9000
UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
UPSTREAM_REAL_IP_HEADER: X-Forwarded-For
UPSTREAM_REAL_IP_RECURSIVE: "off"
PROXY_READ_TIMEOUT: 120
CLIENT_MAX_BODY_SIZE: 50m
depends_on:
backend:
condition: service_started
websocket:
condition: service_started
volumes:
- sites:/home/frappe/frappe-bench/sites
ports:
- "8080:8080"
labels:
- traefik.enable=true
- traefik.http.routers.erpnext.rule=Host(`erp.oasisvape.co.nz`)
- traefik.http.routers.erpnext.entrypoints=websecure
- traefik.http.routers.erpnext.tls.certresolver=letsencrypt
- traefik.http.services.erpnext.loadbalancer.server.port=8080
- traefik.docker.network=traefik-network
networks:
- erpnext-network
- traefik-network
# 其他ERPNext服务...
queue-default:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
command:
- bench
- worker
- --queue
- default
depends_on:
configurator:
condition: service_completed_successfully
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
queue-short:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
command:
- bench
- worker
- --queue
- short
depends_on:
configurator:
condition: service_completed_successfully
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
queue-long:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
command:
- bench
- worker
- --queue
- long
depends_on:
configurator:
condition: service_completed_successfully
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
scheduler:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
command:
- bench
- schedule
depends_on:
configurator:
condition: service_completed_successfully
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
websocket:
image: frappe/erpnext:${ERPNEXT_VERSION}
restart: unless-stopped
command:
- node
- /home/frappe/frappe-bench/apps/frappe/socketio.js
depends_on:
configurator:
condition: service_completed_successfully
volumes:
- sites:/home/frappe/frappe-bench/sites
networks:
- erpnext-network
volumes:
sites:
db-data:
redis-cache-data:
redis-queue-data:
networks:
erpnext-network:
driver: bridge
traefik-network:
external: true
==== 4. Strapi CMS 部署 ====
# docker-compose-strapi.yml
version: '3.8'
services:
strapi:
image: strapi_infra-strapi:latest
container_name: strapi_cms
restart: unless-stopped
environment:
DATABASE_CLIENT: postgres
DATABASE_HOST: strapi_postgres
DATABASE_PORT: 5432
DATABASE_NAME: strapi_db
DATABASE_USERNAME: strapi_user
DATABASE_PASSWORD: 35@Riccarton
DATABASE_SSL: false
DATABASE_SCHEMA: strapi_schema
NODE_ENV: production
HOST: 0.0.0.0
PORT: 1337
TZ: Pacific/Auckland
volumes:
- strapi_app_data:/srv/app
labels:
- traefik.enable=true
- traefik.http.routers.strapi.rule=Host(`cms.oasisvape.co.nz`)
- traefik.http.routers.strapi.entrypoints=websecure
- traefik.http.routers.strapi.tls.certresolver=letsencrypt
- traefik.http.services.strapi.loadbalancer.server.port=1337
networks:
- strapi_network
- traefik-network
volumes:
strapi_app_data:
driver: local
networks:
strapi_network:
external: true
traefik-network:
==== 5. n8n 工作流自动化 ====
# docker-compose-n8n.yml
version: '3.8'
services:
n8n:
image: n8nio/n8n:1.100.1
restart: unless-stopped
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=strapi_postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=strapi_db
- DB_POSTGRESDB_SCHEMA=n8n_schema
- DB_POSTGRESDB_USER=strapi_user
- DB_POSTGRESDB_PASSWORD=35@Riccarton
- GENERIC_TIMEZONE=Pacific/Auckland
- TZ=Pacific/Auckland
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=35@Riccarton
- N8N_HOST=n8n.oasisvape.co.nz
- N8N_PORT=5678
- N8N_SECURE_COOKIE=false
- WEBHOOK_TUNNEL_URL=https://n8n.oasisvape.co.nz
ports:
- "5678:5678"
volumes:
- ./data:/home/node/.n8n
- ./logs:/var/log/n8n
networks:
- strapi_network
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(`n8n.oasisvape.co.nz`)"
- "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
networks:
strapi_network:
external: true
traefik-network:
==== 6. DokuWiki 文档系统 ====
# docker-compose-dokuwiki.yml
version: '3.8'
services:
dokuwiki:
image: lscr.io/linuxserver/dokuwiki:latest
container_name: dokuwiki
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Pacific/Auckland
volumes:
- ./data:/config
- ./logs:/var/log/dokuwiki
ports:
- "8081:80"
networks:
- strapi_network
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.dokuwiki.rule=Host(`wiki.oasisvape.co.nz`)"
- "traefik.http.routers.dokuwiki.entrypoints=websecure"
- "traefik.http.routers.dokuwiki.tls.certresolver=letsencrypt"
- "traefik.http.services.dokuwiki.loadbalancer.server.port=80"
networks:
strapi_network:
external: true
traefik-network:
==== 7. 监控系统 ====
# docker-compose.yml (监控系统)
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- ./data/prometheus:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--storage.tsdb.retention.time=200h'
- '--web.enable-lifecycle'
- '--web.enable-admin-api'
environment:
- TZ=Pacific/Auckland
networks:
- monitoring
- traefik-network
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
privileged: true
devices:
- /dev/kmsg:/dev/kmsg
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
ports:
- "8180:8080"
environment:
- TZ=Pacific/Auckland
networks:
- monitoring
- traefik-network
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- ./data/grafana:/var/lib/grafana
- ./data/grafana/logs:/var/log/grafana
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=35@Riccarton
- GF_USERS_ALLOW_SIGN_UP=false
- GF_INSTALL_PLUGINS=grafana-piechart-panel,grafana-worldmap-panel
- TZ=Pacific/Auckland
networks:
- monitoring
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.oasisvape.co.nz`)"
- "traefik.http.routers.grafana.entrypoints=websecure"
- "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
networks:
monitoring:
driver: bridge
name: monitoring
traefik-network:
external: true
volumes:
prometheus_data:
-----
===== 🔧 网络安全配置 =====
==== 防火墙设置 ====
# 启用UFW
ufw enable
# 开放必要端口
ufw allow 22/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
# 关闭其他端口
ufw deny 3000 # Grafana
ufw deny 5678 # n8n
ufw deny 8080 # ERPNext
ufw deny 8081 # DokuWiki
ufw deny 8180 # cAdvisor
ufw deny 9090 # Prometheus
# 查看状态
ufw status
==== SSL证书管理 ====
* **证书类型**: Let's Encrypt
* **挑战方式**: HTTP Challenge
* **存储位置**: /letsencrypt/acme.json
* **自动续期**: Traefik自动处理
-----
===== 📊 监控配置 =====
==== Prometheus 配置 ====
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
- job_name: 'traefik'
static_configs:
- targets: ['traefik:8080']
==== Grafana 配置 ====
* **默认用户**: admin
* **默认密码**: 35@Riccarton
* **时区**: Pacific/Auckland
* **插件**: grafana-piechart-panel, grafana-worldmap-panel
-----
===== 🚀 部署流程 =====
==== 1. 初始化部署 ====
# 进入项目目录
cd /opt/discountvapor-it
# 创建网络
docker network create traefik-network
docker network create strapi_network
docker network create discountvapor-it_erpnext-network
docker network create monitoring
# 启动Traefik
docker compose -f docker-compose-traefik.yml up -d
# 启动PostgreSQL
docker compose -f docker-compose-postgres.yml up -d
# 启动ERPNext
docker compose -f docker-compose-erpnext.yml up -d
# 启动Strapi
docker compose -f docker-compose-strapi.yml up -d
# 启动n8n
docker compose -f docker-compose-n8n.yml up -d
# 启动DokuWiki
docker compose -f docker-compose-dokuwiki.yml up -d
# 启动监控系统
docker compose up -d
==== 2. 服务验证 ====
# 检查所有容器状态
docker ps
# 检查网络连接
docker network ls
# 检查Traefik路由
docker logs traefik
# 验证SSL证书
curl -I https://erp.oasisvape.co.nz
curl -I https://cms.oasisvape.co.nz
curl -I https://n8n.oasisvape.co.nz
curl -I https://wiki.oasisvape.co.nz
curl -I https://grafana.oasisvape.co.nz
==== 3. 防火墙配置 ====
# 配置防火墙
ufw enable
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw deny 3000
ufw deny 5678
ufw deny 8080
ufw deny 8081
ufw deny 8180
ufw deny 9090
-----
===== 🔍 故障排查 =====
==== 常见问题 ====
===== 1. SSL证书问题 =====
# 检查acme.json权限
ls -la traefik/acme.json
# 重启Traefik
docker compose -f docker-compose-traefik.yml restart
===== 2. 服务无法访问 =====
# 检查容器状态
docker ps -a
# 检查网络
docker network inspect traefik-network
# 查看服务日志
docker logs
===== 3. 数据库连接问题 =====
# 检查数据库容器
docker logs strapi_postgres
# 检查网络连接
docker exec -it strapi_cms ping strapi_postgres
==== 日志查看 ====
# 查看所有服务日志
docker logs traefik
docker logs erpnext-frontend
docker logs strapi_cms
docker logs n8n-automation
docker logs dokuwiki
docker logs grafana
-----
===== 📋 访问信息汇总 =====
^ 服务 ^ 域名 ^ 登录信息 ^ 状态 ^
| ERPNext | https://erp.oasisvape.co.nz | 管理员账号 | ✅ 正常 |
| Strapi CMS | https://cms.oasisvape.co.nz | 管理员账号 | ✅ 正常 |
| n8n | https://n8n.oasisvape.co.nz | admin / 35@Riccarton | ✅ 正常 |
| DokuWiki | https://wiki.oasisvape.co.nz | 管理员账号 | ✅ 正常 |
| Grafana | https://grafana.oasisvape.co.nz | admin / 35@Riccarton | ✅ 正常 |
| Traefik Dashboard | https://traefik.oasisvape.co.nz | - | ✅ 正常 |
-----
===== 🔄 维护和更新 =====
==== 服务更新 ====
# 更新特定服务
docker compose -f docker-compose-xxx.yml pull
docker compose -f docker-compose-xxx.yml up -d
# 更新所有服务
docker compose -f docker-compose-traefik.yml pull
docker compose -f docker-compose-erpnext.yml pull
docker compose -f docker-compose-strapi.yml pull
docker compose -f docker-compose-n8n.yml pull
docker compose -f docker-compose-dokuwiki.yml pull
docker compose pull
==== 备份策略 ====
# 备份配置文件
cp docker-compose-*.yml config_backup/
cp .env config_backup/
cp traefik/traefik.yml config_backup/
# 备份数据
tar -czf backup-$(date +%Y%m%d).tar.gz data/
-----
===== 📞 技术支持 =====
* **项目文档**: https://wiki.oasisvape.co.nz
* **监控面板**: https://grafana.oasisvape.co.nz
* **联系邮箱**: discountvapor2025@gmail.com
* **最后更新**: 2025-01-06