====== 🚀 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