Dujiao-Next Docker Compose 部署完整记录:PostgreSQL + Redis + Nginx + HTTPS
这篇文章记录一次在 Linux 服务器上部署 Dujiao-Next 的完整过程。
最终方案:
1 2 3 4 5 6 7
| 前台地址:https://shop.example.com 后台地址:https://admin.example.com 部署目录:/opt/dujiao-next 数据库:PostgreSQL 缓存/队列:Redis 反向代理:Nginx HTTPS:Certbot + Let's Encrypt
|
本文采用生产环境更推荐的 PostgreSQL + Redis 方案,而不是 SQLite。所有涉及隐私的信息,比如真实域名、服务器 IP、邮箱、密码,都用占位符替代。
一、准备工作
假设你已经有:
1 2 3 4 5 6
| 服务器系统:Debian / Ubuntu 服务器 IP:YOUR_SERVER_IP 主域名:example.com 前台域名:shop.example.com 后台域名:admin.example.com 邮箱:[email protected]
|
先在域名 DNS 里添加两条 A 记录:
1 2
| shop A YOUR_SERVER_IP admin A YOUR_SERVER_IP
|
如果使用 Cloudflare,建议部署和申请证书阶段先关闭代理,也就是使用 仅 DNS / 灰云。等 HTTPS 成功后,再按需开启代理。
二、登录服务器
下面默认以 root 用户执行。如果你不是 root 用户,可以在命令前加 sudo。
三、修复主机名解析问题,可选但推荐
有些服务器执行 sudo 时会出现:
1
| sudo: unable to resolve host your-hostname: Name or service not known
|
可以这样修复:
1
| echo "127.0.1.1 $(hostname)" >> /etc/hosts
|
检查:
确保里面有类似:
四、安装基础组件、Docker、Nginx、Certbot
先更新软件源并安装基础依赖:
1 2
| apt update apt install -y ca-certificates curl gnupg openssl python3 python3-yaml nginx certbot python3-certbot-nginx dnsutils
|
卸载可能冲突的旧 Docker 包:
1 2 3
| for pkg in docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc; do apt remove -y "$pkg" || true done
|
添加 Docker 官方仓库:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| . /etc/os-release
if [ "$ID" != "ubuntu" ] && [ "$ID" != "debian" ]; then echo "当前脚本只适合 Ubuntu/Debian。你的系统是:$ID" exit 1 fi
CODENAME="${UBUNTU_CODENAME:-$VERSION_CODENAME}"
install -m 0755 -d /etc/apt/keyrings curl -fsSL "https://download.docker.com/linux/${ID}/gpg" -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${ID} ${CODENAME} stable" | \ tee /etc/apt/sources.list.d/docker.list > /dev/null
|
安装 Docker Engine 和 Compose 插件:
1 2
| apt update apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
启动 Docker:
1
| systemctl enable --now docker
|
检查 Docker:
1 2 3
| docker --version docker compose version docker run hello-world
|
五、创建部署目录
1 2
| mkdir -p /opt/dujiao-next/{config,data/db,data/uploads,data/logs,data/redis,data/postgres} cd /opt/dujiao-next
|
给数据目录写入权限:
1
| chmod -R 0777 ./data/logs ./data/db ./data/uploads ./data/redis ./data/postgres
|
六、下载 Dujiao-Next 配置模板
1 2 3
| cd /opt/dujiao-next
curl -L https://raw.githubusercontent.com/dujiao-next/dujiao-next/main/config.yml.example -o ./config/config.yml
|
七、生成 .env 环境变量文件
这里会自动生成 Redis 密码、PostgreSQL 密码、后台初始密码等信息。
为了写博客,下面使用占位符风格。实际执行时建议保留 openssl rand 自动生成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| cd /opt/dujiao-next
export APP_SECRET="$(openssl rand -hex 32)" export JWT_SECRET="$(openssl rand -hex 32)" export USER_JWT_SECRET="$(openssl rand -hex 32)" export REDIS_PASSWORD="$(openssl rand -hex 24)" export POSTGRES_PASSWORD="$(openssl rand -hex 24)"
export ADMIN_USERNAME="admin" export ADMIN_PASSWORD="Admin$(openssl rand -hex 10)"
cat > .env <<EOF TAG=latest TZ=Asia/Shanghai
API_PORT=8080 USER_PORT=8081 ADMIN_PORT=8082
DJ_DEFAULT_ADMIN_USERNAME=${ADMIN_USERNAME} DJ_DEFAULT_ADMIN_PASSWORD=${ADMIN_PASSWORD}
REDIS_PASSWORD=${REDIS_PASSWORD}
POSTGRES_DB=dujiao_next POSTGRES_USER=dujiao POSTGRES_PASSWORD=${POSTGRES_PASSWORD} EOF
|
查看生成结果:
1
| cat /opt/dujiao-next/.env
|
你会看到类似:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| TAG=latest TZ=Asia/Shanghai
API_PORT=8080 USER_PORT=8081 ADMIN_PORT=8082
DJ_DEFAULT_ADMIN_USERNAME=admin DJ_DEFAULT_ADMIN_PASSWORD=Adminxxxxxxxxxxxxxxxxxxxx
REDIS_PASSWORD=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx POSTGRES_DB=dujiao_next POSTGRES_USER=dujiao POSTGRES_PASSWORD=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
请务必保存后台初始密码,首次登录后马上修改。
八、修改 config.yml
这一步会把 Dujiao-Next 配置为 PostgreSQL + Redis 模式。
先加载 .env:
1 2 3 4 5 6 7 8 9 10 11
| cd /opt/dujiao-next
set -a . /opt/dujiao-next/.env set +a
export APP_SECRET="$(openssl rand -hex 32)" export JWT_SECRET="$(openssl rand -hex 32)" export USER_JWT_SECRET="$(openssl rand -hex 32)" export ADMIN_USERNAME="${DJ_DEFAULT_ADMIN_USERNAME}" export ADMIN_PASSWORD="${DJ_DEFAULT_ADMIN_PASSWORD}"
|
然后执行 Python 脚本修改配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| python3 <<'PY' import os import yaml from pathlib import Path
path = Path("/opt/dujiao-next/config/config.yml") cfg = yaml.safe_load(path.read_text())
cfg.setdefault("app", {}) cfg["app"]["secret_key"] = os.environ["APP_SECRET"]
cfg.setdefault("server", {}) cfg["server"]["mode"] = "release" cfg.setdefault("server", {}).setdefault("log", {}) cfg["server"]["log"]["dir"] = "/app/logs"
cfg.setdefault("database", {}) cfg["database"]["driver"] = "postgres" cfg["database"]["dsn"] = ( f"host=postgres user={os.environ['POSTGRES_USER']} " f"password={os.environ['POSTGRES_PASSWORD']} " f"dbname={os.environ['POSTGRES_DB']} " "port=5432 sslmode=disable TimeZone=Asia/Shanghai" ) cfg["database"]["pool"] = { "max_open_conns": 25, "max_idle_conns": 5, "conn_max_lifetime_seconds": 3600, "conn_max_idle_time_seconds": 600, }
cfg.setdefault("jwt", {}) cfg["jwt"]["secret"] = os.environ["JWT_SECRET"]
cfg.setdefault("user_jwt", {}) cfg["user_jwt"]["secret"] = os.environ["USER_JWT_SECRET"]
cfg.setdefault("bootstrap", {}) cfg["bootstrap"]["default_admin_username"] = os.environ["ADMIN_USERNAME"] cfg["bootstrap"]["default_admin_password"] = os.environ["ADMIN_PASSWORD"]
cfg.setdefault("redis", {}) cfg["redis"].update({ "enabled": True, "host": "redis", "port": 6379, "password": os.environ["REDIS_PASSWORD"], "db": 0, "prefix": "dj", })
cfg.setdefault("queue", {}) cfg["queue"].update({ "enabled": True, "host": "redis", "port": 6379, "password": os.environ["REDIS_PASSWORD"], "db": 1, "concurrency": 10, "queues": { "default": 10, "critical": 5, }, })
path.write_text(yaml.safe_dump(cfg, allow_unicode=True, sort_keys=False)) PY
|
检查配置是否生效:
1 2 3
| grep -n "driver:" /opt/dujiao-next/config/config.yml grep -n "host=postgres" /opt/dujiao-next/config/config.yml grep -n "host: redis" /opt/dujiao-next/config/config.yml
|
正常应该看到类似:
1 2 3 4
| driver: postgres dsn: host=postgres ... host: redis host: redis
|
踩坑:No module named 'yaml'
如果执行 Python 脚本时出现:
1
| ModuleNotFoundError: No module named 'yaml'
|
说明缺少 python3-yaml,重新安装即可:
1 2 3
| apt update apt install -y python3-yaml python3 -c "import yaml; print('yaml ok')"
|
九、创建 Docker Compose 文件
创建 /opt/dujiao-next/docker-compose.postgres.yml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| cd /opt/dujiao-next
cat > docker-compose.postgres.yml <<'EOF' services: redis: image: redis:7-alpine container_name: dujiaonext-redis restart: unless-stopped environment: REDIS_PASSWORD: ${REDIS_PASSWORD} command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD}"] volumes: - ./data/redis:/data healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 3s retries: 10 networks: - dujiao-net
postgres: image: postgres:16-alpine container_name: dujiaonext-postgres restart: unless-stopped environment: TZ: ${TZ} POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - ./data/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 networks: - dujiao-net
api: image: dujiaonext/api:${TAG} container_name: dujiaonext-api restart: unless-stopped environment: TZ: ${TZ} DJ_DEFAULT_ADMIN_USERNAME: ${DJ_DEFAULT_ADMIN_USERNAME} DJ_DEFAULT_ADMIN_PASSWORD: ${DJ_DEFAULT_ADMIN_PASSWORD} ports: - "127.0.0.1:${API_PORT}:8080" volumes: - ./config/config.yml:/app/config.yml:ro - ./data/uploads:/app/uploads - ./data/logs:/app/logs depends_on: redis: condition: service_healthy postgres: condition: service_healthy healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/health"] interval: 10s timeout: 3s retries: 10 networks: - dujiao-net
user: image: dujiaonext/user:${TAG} container_name: dujiaonext-user restart: unless-stopped environment: TZ: ${TZ} ports: - "127.0.0.1:${USER_PORT}:80" depends_on: api: condition: service_healthy networks: - dujiao-net
admin: image: dujiaonext/admin:${TAG} container_name: dujiaonext-admin restart: unless-stopped environment: TZ: ${TZ} ports: - "127.0.0.1:${ADMIN_PORT}:80" depends_on: api: condition: service_healthy networks: - dujiao-net
networks: dujiao-net: driver: bridge EOF
|
这里有几个安全点:
1 2 3 4 5 6
| Redis 没有暴露 6379 到公网 PostgreSQL 没有暴露 5432 到公网 API 只绑定 127.0.0.1:8080 前台只绑定 127.0.0.1:8081 后台只绑定 127.0.0.1:8082 公网访问统一走 Nginx
|
十、启动 Dujiao-Next
1 2 3 4 5
| cd /opt/dujiao-next
docker compose --env-file .env -f docker-compose.postgres.yml pull docker compose --env-file .env -f docker-compose.postgres.yml up -d docker compose --env-file .env -f docker-compose.postgres.yml ps
|
正常应该看到 5 个容器:
1 2 3 4 5
| dujiaonext-redis dujiaonext-postgres dujiaonext-api dujiaonext-user dujiaonext-admin
|
并且 Redis、PostgreSQL、API 应该是 healthy。
测试本机服务:
1 2 3
| curl -fsS http://127.0.0.1:8080/health curl -I http://127.0.0.1:8081 curl -I http://127.0.0.1:8082
|
正常结果大致是:
1 2 3
| {"status":"ok"} HTTP/1.1 200 OK HTTP/1.1 200 OK
|
踩坑:只 pull 了,没有真正 up -d
如果你执行完后访问:
1
| curl -fsS http://127.0.0.1:8080/health
|
出现:
1
| curl: (7) Failed to connect to 127.0.0.1 port 8080
|
先检查容器是否真的启动:
1
| docker compose --env-file .env -f docker-compose.postgres.yml ps
|
如果没有容器,就重新执行:
1
| docker compose --env-file .env -f docker-compose.postgres.yml up -d
|
十一、安装并配置 Nginx 反向代理
先确保 Nginx 已安装:
创建配置目录:
1
| mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
写入 Nginx 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| cat > /etc/nginx/sites-available/dujiao-next.conf <<'EOF' server { listen 80; server_name shop.example.com;
location / { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location = /sitemap.xml { proxy_pass http://127.0.0.1:8080/sitemap.xml; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location = /robots.txt { proxy_pass http://127.0.0.1:8080/robots.txt; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location /uploads/ { proxy_pass http://127.0.0.1:8080/uploads/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
server { listen 80; server_name admin.example.com;
location / { proxy_pass http://127.0.0.1:8082; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
location /uploads/ { proxy_pass http://127.0.0.1:8080/uploads/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } EOF
|
启用配置:
1 2 3 4 5 6
| ln -sf /etc/nginx/sites-available/dujiao-next.conf /etc/nginx/sites-enabled/dujiao-next.conf rm -f /etc/nginx/sites-enabled/default
nginx -t systemctl enable --now nginx systemctl reload nginx
|
测试 HTTP:
1 2
| curl -I http://shop.example.com curl -I http://admin.example.com
|
正常应该看到:
十二、Nginx 端口占用问题处理
如果启动 Nginx 时出现:
1
| bind() to 0.0.0.0:80 failed (98: Address already in use)
|
说明 80 端口已经被占用。
先查看端口:
1
| ss -ltnp | grep -E ':80|:443'
|
如果发现已有 Nginx 进程占用,但 systemd 认为 Nginx 没启动,可以清理旧进程:
1 2 3 4 5 6 7 8 9 10 11 12 13
| nginx -s quit || true sleep 2
pkill -TERM nginx || true sleep 2
pkill -9 nginx || true rm -f /run/nginx.pid /var/run/nginx.pid
systemctl reset-failed nginx nginx -t systemctl start nginx systemctl status nginx --no-pager -l
|
看到下面状态就正常了:
1
| Active: active (running)
|
十三、申请 HTTPS 证书
确认 Certbot 安装:
如果没有安装:
1 2
| apt update apt install -y certbot python3-certbot-nginx
|
申请证书:
1 2 3 4 5 6 7
| certbot --nginx \ -d shop.example.com \ -d admin.example.com \ --email [email protected] \ --agree-tos \ --no-eff-email \ --redirect
|
成功后会看到类似:
1 2
| Successfully received certificate. Congratulations! You have successfully enabled HTTPS on https://shop.example.com and https://admin.example.com
|
测试 HTTPS:
1 2
| curl -I https://shop.example.com curl -I https://admin.example.com
|
检查自动续期:
十四、访问后台
最终访问地址:
1 2
| 前台:https://shop.example.com 后台:https://admin.example.com
|
查看后台初始账号和密码:
1 2
| cd /opt/dujiao-next grep DJ_DEFAULT_ADMIN .env
|
示例:
1 2
| DJ_DEFAULT_ADMIN_USERNAME=admin DJ_DEFAULT_ADMIN_PASSWORD=Adminxxxxxxxxxxxxxxxxxxxx
|
登录后台后,第一件事就是修改后台密码。
十五、常用维护命令
进入部署目录:
查看容器状态:
1
| docker compose --env-file .env -f docker-compose.postgres.yml ps
|
查看 API 日志:
1
| docker compose --env-file .env -f docker-compose.postgres.yml logs -f api
|
查看最近 200 行 API 日志:
1
| docker compose --env-file .env -f docker-compose.postgres.yml logs --tail=200 api
|
查看 PostgreSQL 日志:
1
| docker compose --env-file .env -f docker-compose.postgres.yml logs --tail=100 postgres
|
查看 Redis 日志:
1
| docker compose --env-file .env -f docker-compose.postgres.yml logs --tail=100 redis
|
重启服务:
1
| docker compose --env-file .env -f docker-compose.postgres.yml restart
|
停止服务:
1
| docker compose --env-file .env -f docker-compose.postgres.yml down
|
启动服务:
1
| docker compose --env-file .env -f docker-compose.postgres.yml up -d
|
更新镜像:
1 2 3 4 5
| cd /opt/dujiao-next
docker compose --env-file .env -f docker-compose.postgres.yml pull docker compose --env-file .env -f docker-compose.postgres.yml up -d docker compose --env-file .env -f docker-compose.postgres.yml ps
|
十六、备份建议
建议定期备份以下目录和文件:
1 2 3 4 5 6
| /opt/dujiao-next/.env /opt/dujiao-next/config/config.yml /opt/dujiao-next/docker-compose.postgres.yml /opt/dujiao-next/data/postgres /opt/dujiao-next/data/uploads /opt/dujiao-next/data/redis
|
可以打包备份:
1 2 3
| cd /opt
tar -czvf dujiao-next-backup-$(date +%F).tar.gz dujiao-next
|
如果数据较大,建议只备份关键目录:
1 2 3 4 5 6 7
| cd /opt/dujiao-next
tar -czvf /root/dujiao-next-config-$(date +%F).tar.gz \ .env \ config/config.yml \ docker-compose.postgres.yml \ data/uploads
|
PostgreSQL 更稳妥的备份方式是使用 pg_dump:
1 2 3 4 5 6
| cd /opt/dujiao-next
docker exec dujiaonext-postgres pg_dump \ -U dujiao \ -d dujiao_next \ > /root/dujiao-next-db-$(date +%F).sql
|
恢复时可以使用:
1
| cat /root/dujiao-next-db-YYYY-MM-DD.sql | docker exec -i dujiaonext-postgres psql -U dujiao -d dujiao_next
|
十七、最终检查清单
部署完成后,建议按下面顺序检查:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| cd /opt/dujiao-next
docker compose --env-file .env -f docker-compose.postgres.yml ps curl -fsS http://127.0.0.1:8080/health curl -I http://127.0.0.1:8081 curl -I http://127.0.0.1:8082
nginx -t systemctl status nginx --no-pager -l
curl -I http://shop.example.com curl -I http://admin.example.com
curl -I https://shop.example.com curl -I https://admin.example.com
certbot renew --dry-run
|
正常情况下:
1 2 3 4 5 6 7
| API health 返回 {"status":"ok"} 前台本地 8081 返回 200 后台本地 8082 返回 200 Nginx active running HTTP 自动跳转 HTTPS HTTPS 返回 200 Certbot dry-run 成功
|
十八、这次部署遇到的几个坑
1. sudo: unable to resolve host
原因是主机名没有写入 /etc/hosts。
修复:
1
| echo "127.0.1.1 $(hostname)" >> /etc/hosts
|
2. ModuleNotFoundError: No module named 'yaml'
原因是缺少 Python YAML 模块。
修复:
1
| apt install -y python3-yaml
|
3. 容器没启动,访问 8080/8081/8082 失败
不要只执行 pull,还要执行:
1
| docker compose --env-file .env -f docker-compose.postgres.yml up -d
|
4. Nginx 配置目录不存在
有些环境没有默认创建这两个目录。
修复:
1
| mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
5. Nginx 80/443 端口被旧进程占用
检查:
1
| ss -ltnp | grep -E ':80|:443'
|
清理旧 Nginx 进程:
1 2 3 4 5
| pkill -TERM nginx || true pkill -9 nginx || true rm -f /run/nginx.pid /var/run/nginx.pid systemctl reset-failed nginx systemctl start nginx
|
6. certbot: command not found
原因是 Certbot 没装。
修复:
1
| apt install -y certbot python3-certbot-nginx
|
总结
这次 Dujiao-Next 部署最终使用的是:
1 2 3 4 5
| Docker Compose 管理服务 PostgreSQL 存储数据 Redis 做缓存和队列 Nginx 反向代理前台和后台 Certbot 自动申请 HTTPS
|
最关键的安全点是:
1 2 3 4 5 6
| Redis 不暴露公网 PostgreSQL 不暴露公网 API/User/Admin 只监听 127.0.0.1 公网只开放 80/443 后台域名不要使用太明显的 admin 也可以 .env、config.yml、数据库和 uploads 目录一定要备份
|
部署完成后,就可以通过:
1 2
| https://shop.example.com https://admin.example.com
|
访问前台和后台。