chore: retire private certificate release path
This commit is contained in:
parent
6a4868b196
commit
798a178927
@ -67,7 +67,7 @@
|
||||
|
||||
- 只有用户明确要求“部署、上线”时才执行生产发布;正式发布只使用已合并的最新 `main`。
|
||||
- Windows 开发机统一使用 `scripts/deploy-from-workstation.ps1`。服务器只运行开发机已构建的 `caiwu_akaunting:<commit>` 镜像,禁止在服务器执行 Composer、npm 或 Docker 构建。
|
||||
- 当前生产入口为 `https://218.93.190.75:8442`;未完成正式域名或公网 `80/443` 验收前,不改成无端口地址,也不在日常发布使用 `-ConfigureHttps`。
|
||||
- 当前生产入口为 `https://caiwu.jiansuntuzhi.cn:8442`;公网仍只使用 `8442`,日常发布不得改成无端口地址。
|
||||
- 发布脚本检测到新增数据库迁移时必须停止,取得负责人明确授权并完成备份后才能使用迁移开关。
|
||||
- 容器内 Laravel 命令使用 `www-data`。发布后只需确认部署 SHA、应用容器健康、受影响的真实页面/接口、迁移是否执行,以及当前和上一版镜像可回滚。
|
||||
- 程序静态资源随应用镜像同源发布;七牛只存用户上传的业务图片、票据和附件。
|
||||
|
||||
@ -19,8 +19,8 @@ fi
|
||||
|
||||
test -s "$SOURCE_CONFIG"
|
||||
test -s "$TARGET_CONFIG"
|
||||
test -s /etc/nginx/caiwuxitong-backend.crt
|
||||
test -s /etc/nginx/caiwuxitong-backend.key
|
||||
test -s /etc/nginx/caiwu-jiansuntuzhi-fullchain.pem
|
||||
test -s /etc/nginx/caiwu-jiansuntuzhi.key
|
||||
|
||||
install -d -m 700 "$BACKUP_DIR"
|
||||
install -m 600 "$TARGET_CONFIG" "$BACKUP_DIR/caiwuxitong-backend-8442.conf"
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
server {
|
||||
listen 8442 ssl default_server;
|
||||
listen [::]:8442 ssl default_server;
|
||||
server_name 218.93.190.75;
|
||||
ssl_certificate /etc/nginx/caiwuxitong-backend.crt;
|
||||
ssl_certificate_key /etc/nginx/caiwuxitong-backend.key;
|
||||
ssl_session_cache shared:CAIWU_BACKEND_SSL:2m;
|
||||
server_name _;
|
||||
ssl_certificate /etc/nginx/caiwu-jiansuntuzhi-fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/caiwu-jiansuntuzhi.key;
|
||||
ssl_session_cache shared:CAIWU_DOMAIN_SSL:2m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
client_max_body_size 12m;
|
||||
@ -16,13 +16,13 @@ server {
|
||||
|
||||
location @plain_http_request {
|
||||
if ($request_uri !~ "^/auth/dingtalk/callback(?:[?]|$)") {
|
||||
return 308 https://218.93.190.75:8442$request_uri;
|
||||
return 308 https://caiwu.jiansuntuzhi.cn:8442$request_uri;
|
||||
}
|
||||
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header Host caiwu.jiansuntuzhi.cn;
|
||||
proxy_set_header X-Forwarded-Host caiwu.jiansuntuzhi.cn;
|
||||
proxy_set_header X-Forwarded-Port 8442;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
@ -30,6 +30,21 @@ server {
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 308 https://caiwu.jiansuntuzhi.cn:8442$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 8442 ssl;
|
||||
listen [::]:8442 ssl;
|
||||
server_name caiwu.jiansuntuzhi.cn;
|
||||
ssl_certificate /etc/nginx/caiwu-jiansuntuzhi-fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/caiwu-jiansuntuzhi.key;
|
||||
ssl_session_cache shared:CAIWU_DOMAIN_SSL:2m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
client_max_body_size 12m;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
@ -44,33 +59,3 @@ server {
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 8442 ssl;
|
||||
listen [::]:8442 ssl;
|
||||
server_name 118.196.84.79;
|
||||
ssl_certificate /etc/nginx/caiwuxitong-backend.crt;
|
||||
ssl_certificate_key /etc/nginx/caiwuxitong-backend.key;
|
||||
ssl_session_cache shared:CAIWU_BACKEND_SSL:2m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
client_max_body_size 12m;
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
allow 118.196.84.79;
|
||||
deny all;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host 218.93.190.75;
|
||||
proxy_set_header X-Forwarded-Host 218.93.190.75;
|
||||
proxy_set_header X-Forwarded-Port 443;
|
||||
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 https;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name 218.93.190.75;
|
||||
|
||||
client_max_body_size 12m;
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /var/www/letsencrypt;
|
||||
default_type text/plain;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
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 http;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name 218.93.190.75;
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /var/www/letsencrypt;
|
||||
default_type text/plain;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 308 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2 default_server;
|
||||
listen [::]:443 ssl http2 default_server;
|
||||
server_name 218.93.190.75;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/caiwuxitong-ip/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/caiwuxitong-ip/privkey.pem;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
client_max_body_size 12m;
|
||||
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header X-Frame-Options SAMEORIGIN always;
|
||||
add_header Referrer-Policy strict-origin-when-cross-origin always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:18088;
|
||||
proxy_http_version 1.1;
|
||||
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 https;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
SERVER_IP="${1:?SERVER_IP is required}"
|
||||
REMOTE_DIR="${2:-/opt/caiwuxitong}"
|
||||
CERTBOT_DIR="/opt/caiwuxitong-certbot"
|
||||
CERT_NAME="caiwuxitong-ip"
|
||||
NGINX_SITE="/etc/nginx/sites-available/caiwuxitong"
|
||||
WEBROOT="/var/www/letsencrypt"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "setup-https.sh must run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$SERVER_IP" != "218.93.190.75" ]; then
|
||||
echo "Refusing to configure an unexpected server IP: $SERVER_IP" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test -f "$REMOTE_DIR/host-nginx-http.conf"
|
||||
test -f "$REMOTE_DIR/host-nginx.conf"
|
||||
curl -fsS -o /dev/null http://127.0.0.1:18088/
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends nginx python3-venv ca-certificates
|
||||
|
||||
install -d -m 755 "$WEBROOT/.well-known/acme-challenge"
|
||||
install -m 644 "$REMOTE_DIR/host-nginx-http.conf" "$NGINX_SITE"
|
||||
ln -sfn "$NGINX_SITE" /etc/nginx/sites-enabled/caiwuxitong
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
nginx -t
|
||||
systemctl enable --now nginx
|
||||
systemctl reload nginx
|
||||
|
||||
if [ ! -x "$CERTBOT_DIR/bin/certbot" ]; then
|
||||
python3 -m venv "$CERTBOT_DIR"
|
||||
"$CERTBOT_DIR/bin/pip" install \
|
||||
--disable-pip-version-check \
|
||||
--no-cache-dir \
|
||||
--timeout 180 \
|
||||
--index-url https://pypi.org/simple \
|
||||
'certbot==5.4.0'
|
||||
fi
|
||||
|
||||
"$CERTBOT_DIR/bin/certbot" --version
|
||||
|
||||
if [ ! -s "/etc/letsencrypt/live/$CERT_NAME/fullchain.pem" ]; then
|
||||
"$CERTBOT_DIR/bin/certbot" certonly \
|
||||
--non-interactive \
|
||||
--agree-tos \
|
||||
--register-unsafely-without-email \
|
||||
--preferred-profile shortlived \
|
||||
--webroot \
|
||||
--webroot-path "$WEBROOT" \
|
||||
--ip-address "$SERVER_IP" \
|
||||
--cert-name "$CERT_NAME"
|
||||
fi
|
||||
|
||||
install -m 644 "$REMOTE_DIR/host-nginx.conf" "$NGINX_SITE"
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
|
||||
cat > /usr/local/sbin/caiwuxitong-certbot-deploy-hook <<'EOF'
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
nginx -t
|
||||
systemctl reload nginx
|
||||
EOF
|
||||
chmod 700 /usr/local/sbin/caiwuxitong-certbot-deploy-hook
|
||||
|
||||
cat > /etc/systemd/system/caiwuxitong-certbot-renew.service <<EOF
|
||||
[Unit]
|
||||
Description=Renew CaiWuXiTong short-lived IP certificate
|
||||
After=network-online.target nginx.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=$CERTBOT_DIR/bin/certbot renew --quiet --deploy-hook /usr/local/sbin/caiwuxitong-certbot-deploy-hook
|
||||
EOF
|
||||
|
||||
cat > /etc/systemd/system/caiwuxitong-certbot-renew.timer <<'EOF'
|
||||
[Unit]
|
||||
Description=Check CaiWuXiTong IP certificate renewal every 8 hours
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 00,08,16:15:00
|
||||
RandomizedDelaySec=30m
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now caiwuxitong-certbot-renew.timer
|
||||
|
||||
curl -fsS -o /dev/null "https://$SERVER_IP/"
|
||||
openssl x509 -in "/etc/letsencrypt/live/$CERT_NAME/fullchain.pem" -noout -subject -issuer -dates
|
||||
systemctl list-timers caiwuxitong-certbot-renew.timer --no-pager
|
||||
echo "HTTPS_READY=https://$SERVER_IP"
|
||||
@ -32,6 +32,7 @@ services:
|
||||
- ./modules:/var/www/html/modules
|
||||
- ./resources:/var/www/html/resources
|
||||
- ./routes:/var/www/html/routes
|
||||
- ./scripts:/var/www/html/scripts
|
||||
- ./tests:/var/www/html/tests
|
||||
networks:
|
||||
- jiangling_net
|
||||
|
||||
@ -82,20 +82,11 @@
|
||||
- 创建持久化数据库卷和运行文件卷;运行文件卷继续保存缓存、临时文件和可回滚的旧上传原件。
|
||||
- 上传应用与 MariaDB 首次全量包,并初始化仅限本机访问的增量 Registry。
|
||||
|
||||
当前云平台仅提供可用的 `TCP 8442`,生产直连地址为 `https://218.93.190.75:8442`。应用容器只绑定服务器本机 `127.0.0.1:18088`,公网由轻量 Nginx 在 `8442` 提供 HTTPS;Registry 的 `5000` 端口仍禁止对公网开放。
|
||||
当前云平台仅提供可用的 `TCP 8442`,生产地址为 `https://caiwu.jiansuntuzhi.cn:8442`。应用容器只绑定服务器本机 `127.0.0.1:18088`,公网由轻量 Nginx 在 `8442` 提供 HTTPS;Registry 的 `5000` 端口仍禁止对公网开放。
|
||||
|
||||
只有云平台已经真正放行 `TCP 80/443`(外网不仅能握手,还能收到服务器响应)时,才执行一次受信任 HTTPS 配置:
|
||||
生产域名使用公共 CA 签发的 `*.jiansuntuzhi.cn` 证书。证书和私钥只保存在服务器 Nginx 私有目录,禁止进入 Git、镜像或发布日志;更换证书后必须执行 `nginx -t`、重载并从外网验证域名和到期时间。
|
||||
|
||||
```powershell
|
||||
.\scripts\deploy-from-workstation.ps1 `
|
||||
-Server 218.93.190.75 `
|
||||
-KeyPath "C:\Users\你的用户名\.ssh\caiwu.pem" `
|
||||
-ConfigureHttps
|
||||
```
|
||||
|
||||
该步骤在服务器安装轻量 Nginx 和独立 Certbot 环境,为公网 IP 申请 Let’s Encrypt 短期证书,并启用每 8 小时检查一次的自动续期。服务器仍不构建任何应用源码或镜像。当前 `80/443` 尚未真正可用时不得执行;继续使用 `8442` 内部证书入口。
|
||||
|
||||
首次打开 `https://218.93.190.75:8442` 后,由负责人或指定人员在网页安装向导中设置管理员账号和密码。当前内部证书可能触发浏览器警告;正式域名或受信任 IP 证书完成后再取消端口和警告。
|
||||
首次打开 `https://caiwu.jiansuntuzhi.cn:8442` 后,由负责人或指定人员在网页安装向导中设置管理员账号和密码。
|
||||
|
||||
## 5. 日常正式发布
|
||||
|
||||
@ -406,7 +397,7 @@ php artisan system-database:reencrypt-upstream-passwords --apply
|
||||
- 发布分支和完整 Git SHA;
|
||||
- 镜像标签;
|
||||
- 服务器 `caiwu_app`、`caiwu_db` 状态;
|
||||
- `https://218.93.190.75:8442` 的实际返回结果和证书状态;
|
||||
- `https://caiwu.jiansuntuzhi.cn:8442` 的实际返回结果和证书状态;
|
||||
- 是否执行数据库迁移;
|
||||
- 本地临时包是否删除;
|
||||
- 本地/服务器保留了几个本项目镜像;
|
||||
|
||||
@ -19,7 +19,6 @@ param(
|
||||
[ValidateRange(24, 8760)]
|
||||
[int]$BuildCacheMaxAgeHours = 720,
|
||||
[switch]$BootstrapServer,
|
||||
[switch]$ConfigureHttps,
|
||||
[switch]$ConfigureDingTalkCallback,
|
||||
[switch]$AllowNonMain,
|
||||
[switch]$AllowMigrations
|
||||
@ -309,7 +308,7 @@ try {
|
||||
|
||||
if (-not $AppUrl) {
|
||||
$AppUrl = if ($Server -eq '218.93.190.75') {
|
||||
"https://${Server}:8442"
|
||||
'https://caiwu.jiansuntuzhi.cn:8442'
|
||||
}
|
||||
else {
|
||||
"https://${Server}"
|
||||
@ -403,11 +402,8 @@ try {
|
||||
deploy/activate-incremental-release.sh `
|
||||
deploy/config-db-init.sh `
|
||||
deploy/update-runtime-url.sh `
|
||||
deploy/setup-https.sh `
|
||||
deploy/configure-dingtalk-callback.sh `
|
||||
deploy/host-nginx-8442-dingtalk.conf `
|
||||
deploy/host-nginx-http.conf `
|
||||
deploy/host-nginx.conf `
|
||||
deploy/setup-incremental-registry.sh `
|
||||
deploy/registry-config.yml `
|
||||
"${sshTarget}:$RemotePath/"
|
||||
@ -517,12 +513,6 @@ try {
|
||||
} '服务器增量激活或健康检查失败。'
|
||||
}
|
||||
|
||||
if ($ConfigureHttps) {
|
||||
Invoke-Native {
|
||||
ssh -i $keyFullPath -o BatchMode=yes $sshTarget "chmod 700 '$RemotePath/setup-https.sh' && '$RemotePath/setup-https.sh' '$Server' '$RemotePath'"
|
||||
} '服务器 HTTPS 配置或证书申请失败。'
|
||||
}
|
||||
|
||||
if ($ConfigureDingTalkCallback) {
|
||||
Invoke-Native {
|
||||
ssh -i $keyFullPath -o BatchMode=yes $sshTarget "chmod 700 '$RemotePath/configure-dingtalk-callback.sh' && '$RemotePath/configure-dingtalk-callback.sh' '$Server' '$RemotePath'"
|
||||
|
||||
@ -13,7 +13,9 @@ class DingTalkCallbackNginxTest extends TestCase
|
||||
$this->assertStringContainsString('error_page 497 = @plain_http_request;', $config);
|
||||
$this->assertStringContainsString('if ($request_uri !~ "^/auth/dingtalk/callback(?:[?]|$)")', $config);
|
||||
$this->assertStringContainsString('proxy_set_header X-Forwarded-Proto http;', $config);
|
||||
$this->assertStringContainsString('return 308 https://218.93.190.75:8442$request_uri;', $config);
|
||||
$this->assertStringContainsString('return 308 https://caiwu.jiansuntuzhi.cn:8442$request_uri;', $config);
|
||||
$this->assertStringContainsString('ssl_certificate /etc/nginx/caiwu-jiansuntuzhi-fullchain.pem;', $config);
|
||||
$this->assertStringNotContainsString('caiwuxitong-backend.crt', $config);
|
||||
}
|
||||
|
||||
public function test_configuration_script_validates_and_restores_on_failure(): void
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user