Ever Gauzy 111.48.2 Docker Compose 部署指南
在 Ubuntu 22.04 上用 Docker Compose 部署 Ever Gauzy v111.48.2(API+Web+PostgreSQL 三服务):镜像选型、.env 环境变量表、持久化目录、down/up 重启恢复闭环实测(约 20 秒全恢复、数据/账号存活)、等价 docker run 与常用运维命令,全部命令与回显实测。
Ever Gauzy 111.48.2 Docker Compose 部署指南
目标:在一台 Ubuntu 22.04 服务器上用 Docker Compose 完整部署 Ever Gauzy v111.48.2(API + Web 前端 + PostgreSQL 三件套),覆盖镜像选型、环境变量、数据持久化、重启恢复闭环与常用运维操作。全文命令与回显均已在 Ubuntu 22.04.5 LTS(Docker Engine 29.8.1 / Docker Compose v5.5.1)环境实测通过,实测版本号
v111.48.2(commit5b3f778e1d12f21992b39b42218fd2fd354c21d6,由GET /api/version返回确认)。
一、环境信息
本节列出实测部署所用的软硬件与组件版本,作为复现基准。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64,12 vCPU / 31 GiB 内存)
- Docker Engine:29.8.1
- Docker Compose:v5.5.1(
docker composev2 插件语法) - Ever Gauzy:v111.48.2(
ghcr.io/ever-co/gauzy-api:latest+ghcr.io/ever-co/gauzy-webapp:latest) - 数据库:PostgreSQL 17(
postgres:17-alpine) - 服务端口:API
8144(容器内 3000)、Web 前端8147(容器内 4200) - 数据目录:
/opt/ever-gauzy/pgdata(数据库文件)、/opt/ever-gauzy/uploads(上传附件),均为 bind mount 持久化 - Compose 项目名:
evergauzy-111.48.2-stack
💡 说明:Ever Gauzy 是开源 ERP/HRM/ATS/时间追踪平台(认知与选型详见 《Ever Gauzy 111.48.2 介绍与选型指南》),平台由 NestJS 后端 API、Angular Web 前端与 PostgreSQL 数据库组成,天然适合 Compose 三服务编排。
二、镜像选型说明
Ever Gauzy 官方在 GitHub Container Registry(ghcr.io)发布预构建镜像,无需本地编译。实测三镜像的体积与角色如下:
docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' | grep -Ei 'gauzy|postgres:17-alpine'
实测输出:
ghcr.io/ever-co/gauzy-webapp:latest 157MB
ghcr.io/ever-co/gauzy-api:latest 3.1GB
postgres:17-alpine 424MB
| 镜像 | 角色 | 体积(实测) | 说明 |
|---|---|---|---|
ghcr.io/ever-co/gauzy-api | API 后端(NestJS) | 3.1GB | 内置 Node.js v24.16.0 运行时、编译产物 main.js 与全部 node_modules,入口 node main.js |
ghcr.io/ever-co/gauzy-webapp | Web 前端(nginx) | 157MB | Angular 构建静态资源 + nginx,nginx 同时把 /api、/graphql 反代到 API 容器 |
postgres:17-alpine | 数据库 | 424MB | Gauzy 生产推荐 PostgreSQL;alpine 变体体积小 |
选型要点:
- API 与 Web 分镜像:官方将前后端拆成两个镜像,前端只依赖
API_BASE_URL指向的 API 地址,二者通过同一宿主机端口对(本文 8144/8147)配合。 - 数据库类型可选:Gauzy 支持
better-sqlite3(默认,仅评估用)、postgres、mysql(DB_TYPE控制),生产一律选postgres,本文采用 PostgreSQL 17。 - 版本固定:官方镜像以
latest滚动发布,生产建议在docker-compose.yml中将image:改为具体版本 tag 或 digest 固定;本文部署时latest对应的实测版本为v111.48.2(已通过 API 版本端点核实)。另有docker-compose.demo.yml形态可一键拉起含演示数据的完整环境,适合快速体验。
三、前置条件
部署前确认服务器满足以下条件:
- 已安装 Docker Engine 与 Compose 插件,且当前用户在
docker组(或使用 sudo)。验证:
docker version --format 'Engine={{.Server.Version}}'
实测输出:
Engine=29.8.1
- 端口
8144、8147未被占用。验证(无输出即空闲):
ss -ltn | grep -E ':8144|:8147'
实测输出(空闲时为空,占用时会列出监听行):
(无输出 = 空闲可用)
- 内存建议 ≥ 4 GiB。实测三容器稳态内存占用很小(见下表),但 API 首次启动建库、运行迁移会短暂冲高:
docker stats --no-stream --format '{{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}' evergauzy-111-web evergauzy-111-api evergauzy-111-pg
实测输出:
evergauzy-111-web 3.785MiB / 31.3GiB 0.00%
evergauzy-111-api 446MiB / 31.3GiB 0.00%
evergauzy-111-pg 31.23MiB / 31.3GiB 0.00%
💡 说明:Web 前端是 nginx 静态服务,内存仅约 4 MiB;API 是常驻 Node 进程,空载约 450 MiB;PostgreSQL 空载约 31 MiB。三服务合计不足 500 MiB,小型团队(数十人规模)2 GiB 内存的服务器即可承载。
- 可访问 ghcr.io 拉取镜像(首次部署需下载约 3.7 GB)。拉取缓慢时可为 Docker 守护进程配置 HTTP 代理后再
docker compose pull。
四、部署步骤
本章按「目录 → .env → docker-compose.yml → 启动 → 验证」的顺序从零部署。全部文件集中在一个 Compose 项目目录中管理。
4.1 创建项目目录与 .env
创建项目目录与两个持久化子目录:
mkdir -p /opt/ever-gauzy/stack /opt/ever-gauzy/pgdata /opt/ever-gauzy/uploads
cd /opt/ever-gauzy/stack
编写 .env 文件(Compose 会自动加载该文件做变量插值)。生产密钥用 openssl rand -hex 64 逐个生成,实测生成的四个密钥如下(本实验环境实测值,正式部署请重新生成自己的密钥):
openssl rand -hex 64
实测输出(示例,本环境实际采用的值):
b24477a8eb51f1088d234377dd515c6bcc8a8707200d4be58a07d31bc68a2d66afc4a670015e744da5cdfbc363e9b2789a47c9905656c13bb6bff87bd976f4e5
将以下内容写入 /opt/ever-gauzy/stack/.env:
NODE_ENV=production
IS_DOCKER=true
APP_NAME=Gauzy
DEMO=false
ALLOW_SUPER_ADMIN_ROLE=true
API_HOST=api
API_PORT=3000
WEB_HOST=webapp
WEB_PORT=4200
API_BASE_URL=http://localhost:8144
CLIENT_BASE_URL=http://localhost:8147
DB_ORM=typeorm
DB_TYPE=postgres
DB_HOST=db
DB_PORT=5432
DB_NAME=gauzy
DB_USER=postgres
DB_PASS=q1w2e3r4
DB_SSL_MODE=false
FILE_PROVIDER=LOCAL
JWT_SECRET=b24477a8eb51f1088d234377dd515c6bcc8a8707200d4be58a07d31bc68a2d66afc4a670015e744da5cdfbc363e9b2789a47c9905656c13bb6bff87bd976f4e5
JWT_REFRESH_TOKEN_SECRET=38f1ee38ad9c19ca4781db5be97e252cf748df9bf318888d150b856339cd98fa657a407af17c63eb8661886760f945cc055d8b41cc93d0b8d1758daae6a9f13a
JWT_VERIFICATION_TOKEN_SECRET=fae51bd89a16a25ca43191fa1a3a8462067369837a86c53500275e059f10f74fd0ba4ac099b662f7fb2375817e06944b24351a11c72dff571442ed040c4bcdc9
EXPRESS_SESSION_SECRET=b16c76bdb4f2fdd1c334bcd135477b3f1479f413a7fbac373327eb166ccdcadc1303d02fd9afc05ade83f7379a362f6eeb9e89db90e8c8d3e99cfec91f14afa6
DEMO_SUPER_ADMIN_EMAIL=admin@ever.co
DEMO_SUPER_ADMIN_PASSWORD=q1w2e3r4
DEMO_ADMIN_EMAIL=local.admin@ever.co
DEMO_ADMIN_PASSWORD=q1w2e3r4
DEMO_EMPLOYEE_EMAIL=employee@ever.co
DEMO_EMPLOYEE_PASSWORD=q1w2e3r4
MAIL_FROM_ADDRESS=gauzy@ever.co
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=
MAIL_PASSWORD=
DEFAULT_CURRENCY=USD
DEFAULT_COUNTRY=US
THROTTLE_ENABLED=true
THROTTLE_TTL=60000
THROTTLE_LIMIT=60000
TRUST_PROXY=1
AUTH_MAX_FAILED_ATTEMPTS=10
AUTH_LOCKOUT_SECONDS=900
⚠️ 注意:
JWT_SECRET等四个安全密钥在生产模式(NODE_ENV=production且DEMO!=true)下不能为空或保留公开默认值,API 启动时会强校验并拒绝启动,这是官方刻意的安全设计;务必用openssl rand -hex 64重新生成。DB_PASS与三个DEMO_*_PASSWORD为本文演示口令,正式部署请替换为强口令。
4.2 编写 docker-compose.yml
将以下内容写入 /opt/ever-gauzy/stack/docker-compose.yml(与实测部署完全一致的配置;显式声明项目名,避免多套部署互相干扰):
name: evergauzy-111.48.2-stack
services:
db:
image: postgres:17-alpine
container_name: evergauzy-111-pg
restart: unless-stopped
environment:
POSTGRES_DB: ${DB_NAME:-gauzy}
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASS:-q1w2e3r4}
volumes:
- /opt/ever-gauzy/pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} || exit 1']
interval: 10s
timeout: 5s
retries: 12
networks:
- evergauzy-net
api:
image: ghcr.io/ever-co/gauzy-api:latest
container_name: evergauzy-111-api
restart: on-failure
environment:
NODE_ENV: ${NODE_ENV:-production}
IS_DOCKER: ${IS_DOCKER:-true}
APP_NAME: ${APP_NAME:-Gauzy}
DEMO: ${DEMO:-false}
ALLOW_SUPER_ADMIN_ROLE: ${ALLOW_SUPER_ADMIN_ROLE:-true}
API_HOST: ${API_HOST:-api}
API_PORT: ${API_PORT:-3000}
API_BASE_URL: ${API_BASE_URL:-http://localhost:8144}
CLIENT_BASE_URL: ${CLIENT_BASE_URL:-http://localhost:8147}
FILE_PROVIDER: ${FILE_PROVIDER:-LOCAL}
DB_ORM: ${DB_ORM:-typeorm}
DB_TYPE: ${DB_TYPE:-postgres}
DB_HOST: ${DB_HOST:-db}
DB_PORT: ${DB_PORT:-5432}
DB_NAME: ${DB_NAME:-gauzy}
DB_USER: ${DB_USER:-postgres}
DB_PASS: ${DB_PASS:-q1w2e3r4}
DB_SSL_MODE: ${DB_SSL_MODE:-false}
JWT_SECRET: ${JWT_SECRET}
JWT_REFRESH_TOKEN_SECRET: ${JWT_REFRESH_TOKEN_SECRET}
JWT_VERIFICATION_TOKEN_SECRET: ${JWT_VERIFICATION_TOKEN_SECRET}
EXPRESS_SESSION_SECRET: ${EXPRESS_SESSION_SECRET}
DEMO_SUPER_ADMIN_EMAIL: ${DEMO_SUPER_ADMIN_EMAIL}
DEMO_SUPER_ADMIN_PASSWORD: ${DEMO_SUPER_ADMIN_PASSWORD}
DEMO_ADMIN_EMAIL: ${DEMO_ADMIN_EMAIL}
DEMO_ADMIN_PASSWORD: ${DEMO_ADMIN_PASSWORD}
DEMO_EMPLOYEE_EMAIL: ${DEMO_EMPLOYEE_EMAIL}
DEMO_EMPLOYEE_PASSWORD: ${DEMO_EMPLOYEE_PASSWORD}
MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS:-gauzy@ever.co}
MAIL_HOST: ${MAIL_HOST:-smtp.gmail.com}
MAIL_PORT: ${MAIL_PORT:-465}
MAIL_USERNAME: ${MAIL_USERNAME:-}
MAIL_PASSWORD: ${MAIL_PASSWORD:-}
DEFAULT_CURRENCY: ${DEFAULT_CURRENCY:-USD}
DEFAULT_COUNTRY: ${DEFAULT_COUNTRY:-US}
THROTTLE_ENABLED: ${THROTTLE_ENABLED:-true}
THROTTLE_TTL: ${THROTTLE_TTL:-60000}
THROTTLE_LIMIT: ${THROTTLE_LIMIT:-60000}
TRUST_PROXY: ${TRUST_PROXY:-1}
AUTH_MAX_FAILED_ATTEMPTS: ${AUTH_MAX_FAILED_ATTEMPTS:-10}
AUTH_LOCKOUT_SECONDS: ${AUTH_LOCKOUT_SECONDS:-900}
entrypoint: './entrypoint.compose.sh'
command: ['node', 'main.js']
depends_on:
db:
condition: service_healthy
ports:
- '8144:3000'
volumes:
- /opt/ever-gauzy/uploads:/srv/gauzy/apps/api/public
networks:
- evergauzy-net
webapp:
image: ghcr.io/ever-co/gauzy-webapp:latest
container_name: evergauzy-111-web
restart: on-failure
environment:
NODE_ENV: ${NODE_ENV:-production}
WEB_HOST: ${WEB_HOST:-webapp}
WEB_PORT: ${WEB_PORT:-4200}
API_HOST: ${API_HOST:-api}
API_PORT: ${API_PORT:-3000}
API_BASE_URL: ${API_BASE_URL:-http://localhost:8144}
CLIENT_BASE_URL: ${CLIENT_BASE_URL:-http://localhost:8147}
DEMO: ${DEMO:-false}
DEFAULT_CURRENCY: ${DEFAULT_CURRENCY:-USD}
entrypoint: './entrypoint.compose.sh'
command: ['nginx', '-g', 'daemon off;']
depends_on:
db:
condition: service_healthy
api:
condition: service_started
ports:
- '8147:4200'
networks:
- evergauzy-net
networks:
evergauzy-net:
driver: bridge
ipam:
config:
- subnet: 10.89.67.0/24
配置要点逐项说明:
name::显式 Compose 项目名,down等操作只影响本项目,避免与其他部署同名互删。db服务:POSTGRES_*三变量初始化数据库;healthcheck 用pg_isready就绪探测,供api以condition: service_healthy精准等待,避免 API 先于数据库启动导致连接失败。api服务:entrypoint.compose.sh是镜像自带的等待脚本(内部用 docker-compose-wait 等DB_HOST:DB_PORT可连后再exec "$@",见 4.4 启动日志);DB_TYPE=postgres切换生产数据库;上传目录 bind mount 到镜像的/srv/gauzy/apps/api/public。webapp服务:nginx 监听容器内 4200,静态托管 Angular 产物并把 API 请求反代到api:3000;映射到宿主8147。API_BASE_URL/CLIENT_BASE_URL:浏览器侧访问地址,端口必须与ports:映射的宿主端口一致(8144/8147),否则前端调不到 API。networks显式子网:固定10.89.67.0/24避免与服务器上其他 Docker 网段冲突,多套环境部署时各选一个空闲网段。
4.3 启动
首次启动(镜像已在本地时):
cd /opt/ever-gauzy/stack
docker compose up -d
实测输出(数据库就绪后 API 才启动,Web 最后启动):
Container evergauzy-111-pg Healthy
Container evergauzy-111-api Starting
Container evergauzy-111-api Started
Container evergauzy-111-pg Waiting
Container evergauzy-111-pg Healthy
Container evergauzy-111-web Starting
Container evergauzy-111-web Started
实测 up -d 命令耗时 11.64s(镜像已拉取的二次部署;首次部署需先完成约 3.7 GB 镜像下载)。若镜像未拉取,先执行 docker compose pull。
API 容器启动日志节选(等待数据库 → exec 主进程):
+ export 'WAIT_HOSTS=db:5432'
+ ./wait
[INFO wait] --------------------------------------------------------
[INFO wait] docker-compose-wait 2.9.0
[INFO wait] ---------------------------
[DEBUG wait] Starting with configuration:
[DEBUG wait] - Hosts to be waiting for: [db:5432]
[INFO wait] Checking availability of host [db:5432]
[INFO wait] Host [db:5432] is now available!
[INFO wait] docker-compose-wait - Everything's fine, the application can now start!
API 就绪日志(启动约 25 秒后;API 会自动对空库执行 ORM 建表,首次启动生成 290 张业务表):
[Nest] 1 - 10/23/2026, 2:41:22 AM LOG [NestApplication] Nest application successfully started +8ms
4.4 验证
依次验证容器状态、API、Web 与账号登录:
docker compose ps --format 'table {{.Name}}\t{{.Service}}\t{{.Status}}'
实测输出:
NAME SERVICE STATUS
evergauzy-111-api api Up 14 seconds
evergauzy-111-pg db Up 25 seconds (healthy)
evergauzy-111-web webapp Up 14 seconds
API 版本与健康检查:
curl -s http://localhost:8144/api/version
实测输出:
{"name":"api","version":"v111.48.2","commit":"5b3f778e1d12f21992b39b42218fd2fd354c21d6"}
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8144/api/health
实测输出:
200
/api/health 的详细结果可在 API 日志中看到,数据库/存储/缓存三项全部 up:
Health check result: {"status":"ok","info":{"database":{"status":"up"},"storage":{"status":"up"},"cache":{"status":"up","cacheType":"memory"}},"error":{},"details":{"database":{"status":"up"},"storage":{"status":"up"},"cache":{"status":"up","cacheType":"memory"}}}
Web 前端首页:
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8147/
实测输出:
200
超级管理员登录(DEMO_SUPER_ADMIN_EMAIL/PASSWORD 在首启时写入数据库,实测登录返回用户对象与 JWT):
curl -s -X POST http://localhost:8144/api/auth/login -H 'Content-Type: application/json' \
-d '{"email":"admin@ever.co","password":"q1w2e3r4"}'
实测输出(节选):
{"user":{"deletedAt":null,"createdAt":"2026-10-23T01:18:09.420Z",...,"firstName":"Super","lastName":"Admin","email":"admin@ever.c...
💡 说明:
DEMO=false时平台只初始化超级管理员账号(来自DEMO_SUPER_ADMIN_EMAIL/PASSWORD),不灌入演示员工/项目/时间记录等业务数据,适合作为干净的生产起点。浏览器访问http://服务器IP:8147/用该账号即可进入管理界面。
五、数据持久化说明
Ever Gauzy 的全部业务数据落两处 bind mount,宿主机目录即数据目录:
| 宿主目录 | 容器内路径 | 内容 |
|---|---|---|
/opt/ever-gauzy/pgdata | /var/lib/postgresql/data(db) | PostgreSQL 全部数据文件 |
/opt/ever-gauzy/uploads | /srv/gauzy/apps/api/public(api) | 头像/附件等上传文件 |
数据库目录实测体积(首启建表 + 种子账号后):
du -sh /opt/ever-gauzy/pgdata
实测输出:
115M /opt/ever-gauzy/pgdata
重启恢复闭环实测(bind mount 数据在容器删除重建后依然保留)。执行完整的 down(删容器+网络)→ up -d(重建):
cd /opt/ever-gauzy/stack
docker compose down
实测输出:
Container evergauzy-111-pg Removed
Network evergauzy-111482-stack_evergauzy-net Removing
Network evergauzy-111482-stack_evergauzy-net Removed
实测 down 耗时 4.28s。随后重建:
docker compose up -d
实测 up -d 耗时 11.64s,恢复轮询(Web 返回 200 且 API 健康检查 200)在 up 返回后 3s 内达成——从发出 down 到全服务恢复约 20 秒。
数据存活验证一:重启前登录过的 admin@ever.co 账号重启后重新登录成功(账号数据存活);验证二:重启前通过 API 创建的任务重启后计数仍为 1(业务数据存活):
curl -s "http://localhost:8144/api/tasks/count?organizationId=8426a8c4-92f6-4fed-9da4-769b33288367" \
-H "Authorization: Bearer $TOKEN" -H "Tenant-Id: 5fc5f20d-9363-4860-b516-883d1c1eb408"
实测输出:
1
结论:pgdata 与 uploads 两个 bind mount 目录即是全部持久化状态,备份这两个目录(或用 pg_dump 逻辑备份)即可整体备份平台。数据库逻辑备份实测:
docker exec evergauzy-111-pg pg_dump -U postgres -d gauzy > /opt/ever-gauzy/gauzy-backup.sql
实测备份产物约 3.4 MB(3365059 字节,仅含种子数据与结构)。
六、环境变量表
Compose 部署的配置全部经 .env → 容器环境变量注入。下表为部署相关核心变量(实测取值来自本环境):
| 变量 | 实测取值 | 说明 |
|---|---|---|
NODE_ENV | production | 运行模式;production 下强校验安全密钥 |
IS_DOCKER | true | 声明运行于镜像环境,影响路径与行为分支 |
DEMO | false | 是否演示模式;false 只种超级管理员账号 |
ALLOW_SUPER_ADMIN_ROLE | true | 允许超级管理员角色(自托管必需) |
API_BASE_URL | http://localhost:8144 | API 对外地址(浏览器可达),须与端口映射一致 |
CLIENT_BASE_URL | http://localhost:8147 | Web 对外地址,邮件里的链接也用它 |
DB_TYPE | postgres | 数据库类型(sqlite/mysql/postgres 可选) |
DB_ORM | typeorm | ORM 层(typeorm/mikro-orm 可选) |
DB_HOST / DB_PORT | db / 5432 | 数据库地址(Compose 服务名)/端口 |
DB_NAME / DB_USER / DB_PASS | gauzy / postgres / q1w2e3r4 | 库名/账号/口令(演示口令,请替换) |
DB_SSL_MODE | false | 数据库 SSL 开关 |
JWT_SECRET 等 4 个密钥 | openssl rand -hex 64 生成 | 访问令牌/刷新令牌/验证令牌/会话签名密钥 |
DEMO_SUPER_ADMIN_EMAIL / PASSWORD | admin@ever.co / q1w2e3r4 | 首启创建的超级管理员 |
DEMO_ADMIN_EMAIL / DEMO_EMPLOYEE_EMAIL | local.admin@ever.co / employee@ever.co | 预留的管理员/员工演示账号 |
FILE_PROVIDER | LOCAL | 文件存储方式(本地目录/S3 等) |
MAIL_HOST / MAIL_PORT | smtp.gmail.com / 465 | 发件 SMTP;不配则邮件功能不可用 |
DEFAULT_CURRENCY / DEFAULT_COUNTRY | USD / US | 新组织的默认币种/国家 |
THROTTLE_ENABLED / THROTTLE_TTL / THROTTLE_LIMIT | true / 60000 / 60000 | API 限流开关/窗口 ms/窗口内次数 |
TRUST_PROXY | 1 | 信任的反向代理跳数,取真实客户端 IP |
AUTH_MAX_FAILED_ATTEMPTS / AUTH_LOCKOUT_SECONDS | 10 / 900 | 登录失败锁定阈值/锁定时长秒 |
API_PORT / WEB_PORT | 3000 / 4200 | 容器内监听端口(与宿主映射解耦) |
💡 说明:Gauzy 的完整变量集有 1000 余项(覆盖集成、AI、支付、Redis 队列等),上表仅收录本部署形态实际注入生效的部分,其余变量保持官方默认即可满足本部署形态。
七、配置参数说明
本节解释几个最容易踩错的关键参数:
API_BASE_URL/CLIENT_BASE_URL与端口映射强绑定:二者是「浏览器视角」的地址。本部署把 API 映射到宿主8144、Web 映射到8147,故分别写http://localhost:8144与http://localhost:8147。若部署到公网域名,应改为https://gauzy.example.com形式,否则前端页面调 API 会跨域失败、邮件里的确认链接也指错地址。DEMO与种子数据:DEMO=false时首启只建超级管理员;DEMO=true会灌入完整演示数据集(员工、项目、时间记录等),适合快速体验但生产禁用。- 安全密钥强校验:
NODE_ENV=production且DEMO!=true时,四个密钥为空或为公开默认值会让 API 拒绝启动(防弱密钥上生产)。这是官方在.env.sample中明文声明的设计,不是故障。 DB_TYPE=postgres依赖链:Gauzy 默认better-sqlite3(单文件,仅评估用)。生产走 PostgreSQL 时,ORM 在首次启动自动完成建表(实测生成 290 张表),无需手工执行迁移脚本。- 限流参数:
THROTTLE_TTL=60000(60 秒窗口)+THROTTLE_LIMIT=60000(窗口内最多 60000 次)是宽松默认,按团队规模调小THROTTLE_LIMIT可抗滥用。 TRUST_PROXY=1:API 置于 nginx 等反代后时必须设置,否则限流与审计记录到的是代理 IP。
八、配置文件挂载
本部署形态下各服务的配置来源如下:
- 数据库初始化参数:经
environment注入(POSTGRES_DB/USER/PASSWORD),无额外配置文件。 - API 配置:全部来自环境变量,无挂载的配置文件;仅需挂载上传目录
/opt/ever-gauzy/uploads:/srv/gauzy/apps/api/public(FILE_PROVIDER=LOCAL时文件落这里)。 - Web(nginx)配置:镜像内置,其模板按
API_BASE_URL等环境变量在启动时渲染,无需自定义挂载;如需加 TLS,可在其上再放一层宿主 nginx/caddy 反代 8147。 .env文件:Compose 自动读取项目目录下的.env做变量插值;修改后执行docker compose up -d重建使变更生效。
九、等价 docker run
不用 Compose 时,以下三条命令等价于上述三服务(先建网络,再按依赖顺序启动)。生产仍建议用 Compose 统一管理:
docker network create --subnet 10.89.67.0/24 evergauzy-net
docker run -d --name evergauzy-111-pg --network evergauzy-net \
-e POSTGRES_DB=gauzy -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=q1w2e3r4 \
-v /opt/ever-gauzy/pgdata:/var/lib/postgresql/data \
postgres:17-alpine
docker run -d --name evergauzy-111-api --network evergauzy-net -p 8144:3000 \
-e NODE_ENV=production -e IS_DOCKER=true -e DEMO=false -e ALLOW_SUPER_ADMIN_ROLE=true \
-e DB_TYPE=postgres -e DB_HOST=db -e DB_PORT=5432 -e DB_NAME=gauzy \
-e DB_USER=postgres -e DB_PASS=q1w2e3r4 \
-e API_BASE_URL=http://localhost:8144 -e CLIENT_BASE_URL=http://localhost:8147 \
-e JWT_SECRET=${JWT_SECRET} -e JWT_REFRESH_TOKEN_SECRET=${JWT_REFRESH_TOKEN_SECRET} \
-e JWT_VERIFICATION_TOKEN_SECRET=${JWT_VERIFICATION_TOKEN_SECRET} \
-e EXPRESS_SESSION_SECRET=${EXPRESS_SESSION_SECRET} \
-e DEMO_SUPER_ADMIN_EMAIL=admin@ever.co -e DEMO_SUPER_ADMIN_PASSWORD=q1w2e3r4 \
-v /opt/ever-gauzy/uploads:/srv/gauzy/apps/api/public \
ghcr.io/ever-co/gauzy-api:latest
docker run -d --name evergauzy-111-web --network evergauzy-net -p 8147:4200 \
-e NODE_ENV=production -e API_HOST=api -e API_PORT=3000 \
-e API_BASE_URL=http://localhost:8144 -e CLIENT_BASE_URL=http://localhost:8147 \
ghcr.io/ever-co/gauzy-webapp:latest
⚠️ 注意:等价
docker run没有健康检查联动,api启动早于数据库就绪时会因连接失败退出重试(镜像策略为失败自动重启),最终仍能起来,但启动顺序不如 Compose 的service_healthy精准。${JWT_SECRET}等值先在 shell 中导出后再执行。
十、常用运维命令
以下命令均在 /opt/ever-gauzy/stack 项目目录下执行(实测环境为 Docker Compose v5.5.1)。
查看服务状态:
docker compose ps
跟踪 API 日志:
docker compose logs -f api
停止/启动(保留容器与数据):
docker compose stop # 实测耗时 0.59s
docker compose start # 实测命令耗时 11.46s,全服务恢复约 15s
删除容器与网络(数据目录不受影响):
docker compose down # 实测耗时 4.28s
修改 .env 后应用配置:
docker compose up -d # 有配置变化的容器会被重建
升级镜像版本:
docker compose pull && docker compose up -d
进入数据库命令行:
docker exec -it evergauzy-111-pg psql -U postgres -d gauzy
逻辑备份与恢复:
docker exec evergauzy-111-pg pg_dump -U postgres -d gauzy > /opt/ever-gauzy/gauzy-backup.sql
cat /opt/ever-gauzy/gauzy-backup.sql | docker exec -i evergauzy-111-pg psql -U postgres -d gauzy
十一、常见问题
Q1:API 容器反复重启,日志报数据库连接失败?
API 的等待脚本最多等 30 秒(docker-compose-wait 默认 Timeout before failure: 30 seconds)。若 PostgreSQL 初始化(大磁盘首格)超过该时长,API 会失败退出;镜像 restart: on-failure 会自动重试,通常下一轮即成功。若持续失败,检查 DB_HOST 是否为服务名 db、DB_PASS 是否与 db 服务的 POSTGRES_PASSWORD 一致。
Q2:浏览器打开 8147 页面正常,但登录/数据请求全部失败?
检查 API_BASE_URL:它是「浏览器」发起 API 请求的目标地址。若写成了容器内地址或未映射的端口(如 http://api:3000、http://localhost:3000),页面就会调不通。必须与 ports: 的宿主映射一致(本文为 http://localhost:8144,公网部署换成对应域名)。
Q3:容器起不来,日志提示安全密钥校验失败?
NODE_ENV=production 且 DEMO=false 时,JWT_SECRET、JWT_REFRESH_TOKEN_SECRET、JWT_VERIFICATION_TOKEN_SECRET、EXPRESS_SESSION_SECRET 任一为空或为公开默认值都会被拒绝启动。用 openssl rand -hex 64 重新生成四把密钥写入 .env 后 docker compose up -d。
Q4:首次启动后登录页账号密码是什么?
DEMO=false 时只有超级管理员:.env 中 DEMO_SUPER_ADMIN_EMAIL/DEMO_SUPER_ADMIN_PASSWORD(本文为 admin@ever.co / q1w2e3r4,生产务必替换强口令)。
Q5:端口 8144/8147 被占用怎么改?
同时改两处保持一致:docker-compose.yml 中对应服务的 ports 宿主端口,以及 .env 的 API_BASE_URL/CLIENT_BASE_URL,然后 docker compose up -d 重建。
Q6:调用 REST API 时带对了 Bearer Token 仍返回 403 Forbidden?
Gauzy 多租户接口要求请求头携带租户 ID,且服务端按原始头大小写精确匹配 Tenant-Id(tenant-id/Tenant-Id 可,Tenant-ID 不行——HTTP 头本应大小写不敏感,这是该版本的实现细节)。实测对比:Tenant-Id 头通过校验,Tenant-ID 头返回 403 {"message":"Forbidden resource",...}。另外值须与 JWT 中的 tenantId 一致。
十二、参考链接
- Ever Gauzy 官方文档(部署):https://docs.ever.co/
- 源码仓库:https://github.com/ever-co/ever-gauzy
- 官方镜像:https://ghcr.io/ever-co/gauzy-api 、https://ghcr.io/ever-co/gauzy-webapp
- 平台内认知篇:《Ever Gauzy 111.48.2 介绍与选型指南》