Compare commits
12 Commits
99afdbd82e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3332c6c940 | ||
|
|
a9ec40a289 | ||
|
|
fb87be680d | ||
|
|
58d65188a1 | ||
|
|
b028e6dd73 | ||
|
|
b93e85b428 | ||
|
|
8fa08f4b98 | ||
|
|
42d14a19e6 | ||
|
|
9a2defc0ee | ||
|
|
538dc1339d | ||
|
|
774cae3c02 | ||
|
|
1e5c48ffdd |
37
.codebuddy/skills/docker-build/SKILL.md
Normal file
37
.codebuddy/skills/docker-build/SKILL.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: docker-build
|
||||||
|
description: 根据dockerfile构建镜像
|
||||||
|
---
|
||||||
|
|
||||||
|
# Docker Build
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
此技能用于协助完成 Docker 镜像的构建
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
根据docker file 构建镜像
|
||||||
|
|
||||||
|
## Core Workflow
|
||||||
|
|
||||||
|
### 1. 清理node1 服务器 ~/dockerbuild/ 目录下,对应项目的文件
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 2. 同步代码到node1 服务器 ~/dockerbuild/ 目录下,对应项目的文件
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 3. 执行docker build 构建镜像
|
||||||
|
|
||||||
|
### 4. 导出镜像,并下载到当前项目对应的把目录下
|
||||||
|
|
||||||
|
## node1服务器信息
|
||||||
|
ip 10.0.3.5
|
||||||
|
用户名 awei
|
||||||
|
已做ssh 互信
|
||||||
|
## 镜像命名
|
||||||
|
- 名字保持和对应目录名称一致
|
||||||
|
- 版本采用月日时分格式,如 04192334(4月19日23时34分)
|
||||||
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,8 +1,10 @@
|
|||||||
# Docker images
|
# Docker images
|
||||||
docker-images/*.tar
|
docker-images/*.tar
|
||||||
|
nginx/*.tar
|
||||||
|
|
||||||
# frp binary (large file)
|
# frp binary (large file)
|
||||||
frpc-client/frp_*.tar.gz
|
frpc-client/frp_*.tar.gz
|
||||||
|
frpc-client/frp.tar.gz.b64
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.idea/
|
.idea/
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
# MEMORY.md
|
|
||||||
|
|
||||||
## 服务器信息
|
|
||||||
|
|
||||||
### node1
|
|
||||||
- **IP**: 10.0.3.5
|
|
||||||
- **用户名**: awei
|
|
||||||
- **SSH 互信**: 已配置
|
|
||||||
|
|
||||||
## Docker 镜像构建流程
|
|
||||||
|
|
||||||
### 关键步骤
|
|
||||||
|
|
||||||
1. **清理服务端目录**(避免文件残留导致问题)
|
|
||||||
```bash
|
|
||||||
ssh awei@10.0.3.5 "rm -rf /tmp/<目录名> && mkdir -p /tmp/<目录名>"
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **上传源码文件**
|
|
||||||
```bash
|
|
||||||
scp <本地文件> awei@10.0.3.5:/tmp/<目录名>/
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **构建镜像**(带版本号)
|
|
||||||
```bash
|
|
||||||
ssh awei@10.0.3.5 "cd /tmp/<目录名> && docker build -t stonelan/<镜像名>:YYYYMMDD -t stonelan/<镜像名>:latest ."
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **导出镜像**
|
|
||||||
```bash
|
|
||||||
ssh awei@10.0.3.5 "docker save -o /tmp/<镜像名>-YYYYMMDD.tar stonelan/<镜像名>:YYYYMMDD"
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **下载到本地**
|
|
||||||
```bash
|
|
||||||
scp awei@10.0.3.5:/tmp/<镜像名>-YYYYMMDD.tar <本地路径>/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 现有镜像
|
|
||||||
|
|
||||||
| 镜像名称 | 版本号 | 基础镜像 | 说明 |
|
|
||||||
|---------|--------|---------|------|
|
|
||||||
| stonelan/nginx | 1.0.1 | nginx:alpine | 反向代理,含自定义配置 |
|
|
||||||
| stonelan/frpc | 1.0.1 | alpine:3.19 | FRP 客户端 v0.61.1 |
|
|
||||||
|
|
||||||
### 注意事项
|
|
||||||
|
|
||||||
- **版本号格式**:语义化版本 `X.Y.Z`(如 1.0.0、1.0.1、1.1.0)
|
|
||||||
- **每次构建必须递增版本号**,避免重复
|
|
||||||
- 构建前先清理服务端临时目录,避免旧文件干扰
|
|
||||||
- 本地 tar.gz 等二进制文件通过 scp 传输正常,无需特殊处理
|
|
||||||
|
|
||||||
### 已知问题
|
|
||||||
|
|
||||||
- **scp 传输速度慢**:Windows OpenSSH 客户端传输速度约 0.76 MB/s(12MB 文件需 2-3 分钟),暂无解决方案
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
navidrome:
|
|
||||||
container_name: navidrome
|
|
||||||
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/deluan/navidrome:pr-4181
|
|
||||||
ports:
|
|
||||||
- "4533:4533"
|
|
||||||
restart: always
|
|
||||||
environment:
|
|
||||||
# 扫描音乐库的计划
|
|
||||||
ND_SCANSCHEDULE: "@every 1h"
|
|
||||||
# 日志级别
|
|
||||||
ND_LOGLEVEL: "info"
|
|
||||||
# 默认语言
|
|
||||||
ND_DEFAULTLANGUAGE: "zh"
|
|
||||||
# 会话超时时间
|
|
||||||
ND_SESSIONTIMEOUT: "24h"
|
|
||||||
# 启用下载功能
|
|
||||||
ND_ENABLEDOWNLOADS: "true"
|
|
||||||
# 启用收藏夹
|
|
||||||
ND_ENABLEFAVOURITES: "true"
|
|
||||||
# 启用共享功能
|
|
||||||
ND_ENABLESHARING: "false"
|
|
||||||
# 在 UI 中启用5星评级
|
|
||||||
ND_ENABLESTARRATING: "true"
|
|
||||||
# 启用转码配置
|
|
||||||
ND_ENABLETRANSCODINGCONFIG: "true"
|
|
||||||
# 转码缓存大小
|
|
||||||
ND_TRANSCODINGCACHESIZE: "2000M"
|
|
||||||
# 图片缓存大小
|
|
||||||
ND_IMAGECACHESIZE: "1000M"
|
|
||||||
# 音乐文件路径
|
|
||||||
ND_MUSICFOLDER: "/music"
|
|
||||||
# 数据路径
|
|
||||||
ND_DATAFOLDER: "/data"
|
|
||||||
volumes:
|
|
||||||
# 将宿主机的数据目录挂载到容器的数据目录,用于数据持久化
|
|
||||||
- "./data:/data"
|
|
||||||
# 将宿主机的音乐目录挂载到容器的音乐目录,只读模式
|
|
||||||
- "./music:/music:ro"
|
|
||||||
networks:
|
|
||||||
- navidrome-net
|
|
||||||
|
|
||||||
networks:
|
|
||||||
navidrome-net:
|
|
||||||
driver: bridge
|
|
||||||
98
acme/README.md
Normal file
98
acme/README.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# 证书管理服务(acme.sh)
|
||||||
|
|
||||||
|
用宿主机上的 [acme.sh](https://github.com/acmesh-official/acme.sh) 管理 Let's Encrypt 证书:
|
||||||
|
纯 Shell 实现,不依赖 Python / snap / Docker 容器。
|
||||||
|
|
||||||
|
## 为什么换成 acme.sh
|
||||||
|
|
||||||
|
之前用 certbot 容器时有个绕不开的别扭点:certbot 的 `--deploy-hook` 在**容器内**执行,
|
||||||
|
而我们要 reload 的 nginx 是**宿主机上的容器**,只能在容器里挂 `docker.sock`(等于把宿主机
|
||||||
|
root 交给容器),或者退而求其次每天无条件发一次 HUP。
|
||||||
|
|
||||||
|
acme.sh 直接跑在宿主机,`--reloadcmd` 天然在宿主机执行,**只在证书真正更新时才 reload**,
|
||||||
|
顺带把 certbot 容器、Dockerfile、docker.sock、compose PATH 问题全部消掉。
|
||||||
|
|
||||||
|
## 架构
|
||||||
|
|
||||||
|
```
|
||||||
|
宿主机 容器
|
||||||
|
───────────────────────────────────── ──────────────────────────
|
||||||
|
acme.sh(~/.acme.sh,自带 cron)
|
||||||
|
├─ 写挑战文件 ──▶ /var/www/certbot ──bind mount(ro)──▶ nginx-proxy
|
||||||
|
├─ 写证书 ──▶ /etc/letsencrypt ──bind mount(ro)──▶ nginx-proxy
|
||||||
|
└─ 续签后执行 reloadcmd: docker kill -s HUP nginx-proxy
|
||||||
|
|
||||||
|
用户 ─▶ frps(80/443) ─▶ frpc ─▶ nginx-proxy(80/8443)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 目录约定
|
||||||
|
|
||||||
|
| 宿主机路径 | 用途 |
|
||||||
|
|---|---|
|
||||||
|
| `/var/www/certbot` | ACME HTTP-01 挑战文件 |
|
||||||
|
| `/etc/letsencrypt/live/<CERT_NAME>/` | 证书(默认 CERT_NAME=stonelan.cn) |
|
||||||
|
| `nginx/ssl.d/` | HTTPS server 块,证书就绪后由 `enable-ssl.sh` 写入 |
|
||||||
|
|
||||||
|
5 个域名合成**一张 SAN 证书**,放在同一个目录,nginx 的 5 个 server 块都引用它。
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd common-server-public/acme
|
||||||
|
chmod +x install.sh issue.sh renew.sh check-cert.sh
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 申请证书(一键引导)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./issue.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
依次完成:建目录 → 起 nginx(此时无 HTTPS 配置)→ 申请证书 → 安装证书 →
|
||||||
|
写入 `ssl.d/` 并重载 nginx。
|
||||||
|
|
||||||
|
可用环境变量覆盖:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
EMAIL=you@example.com \
|
||||||
|
CERT_NAME=stonelan.cn \
|
||||||
|
DOMAINS="fastgpt.stonelan.cn gitea.stonelan.cn image.stonelan.cn registry.stonelan.cn www.stonelan.cn" \
|
||||||
|
sudo -E ./issue.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 自动续签
|
||||||
|
|
||||||
|
`install.sh` 已让 acme.sh 自己写入 cron,**无需额外配置**。
|
||||||
|
|
||||||
|
建议再加一条兜底告警(`crontab.example`):
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 8 * * * bash <绝对路径>/check-cert.sh >> /var/log/acme-check.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
```bash
|
||||||
|
acme.sh --list # 已申请的证书
|
||||||
|
acme.sh --cron --debug 2 # 带调试跑一次续签
|
||||||
|
./check-cert.sh # 剩余天数
|
||||||
|
|
||||||
|
# 确认 nginx 只加载了 HTTP 配置(冷启动时属正常)
|
||||||
|
docker exec nginx-proxy nginx -T | grep -c "listen 8443"
|
||||||
|
|
||||||
|
# ACME 路径可达性
|
||||||
|
echo probe | sudo tee /var/www/certbot/.well-known/acme-challenge/test
|
||||||
|
curl -i http://fastgpt.stonelan.cn/.well-known/acme-challenge/test
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. 需要 root(或 sudo)运行:要写 `/etc/letsencrypt` 和 `/var/www`
|
||||||
|
2. nginx 容器 bind mount 的是**宿主机路径**,宿主机上这两个目录必须存在,
|
||||||
|
否则 docker 会自动创建成 root 所有的空目录
|
||||||
|
3. 挑战文件需要让容器内 nginx 可读,目录保持 755(`issue.sh` 已处理)
|
||||||
|
4. CA 已显式固定为 Let's Encrypt(acme.sh 3.x 默认是 ZeroSSL)
|
||||||
|
5. 证书有效期 90 天,acme.sh 默认在剩余 30 天内续签
|
||||||
32
acme/check-cert.sh
Normal file
32
acme/check-cert.sh
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# 检查证书剩余有效期,低于阈值时以非 0 退出,便于接入告警。
|
||||||
|
# 自动续签有可能静默失败,必须有一个独立的检查点。
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CERT_NAME="${CERT_NAME:-stonelan.cn}"
|
||||||
|
CERT="${CERT:-/etc/letsencrypt/live/$CERT_NAME/cert.pem}"
|
||||||
|
WARN_DAYS="${WARN_DAYS:-20}"
|
||||||
|
|
||||||
|
if [ ! -f "$CERT" ]; then
|
||||||
|
echo "证书不存在:$CERT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
end="$(openssl x509 -enddate -noout -in "$CERT" | cut -d= -f2)"
|
||||||
|
end_ts="$(date -d "$end" +%s)"
|
||||||
|
days=$(( (end_ts - $(date +%s)) / 86400 ))
|
||||||
|
|
||||||
|
echo "证书文件:$CERT"
|
||||||
|
echo "到期时间:$end(剩余 $days 天)"
|
||||||
|
openssl x509 -subject -issuer -noout -in "$CERT" | sed 's/^/ /'
|
||||||
|
openssl x509 -text -noout -in "$CERT" \
|
||||||
|
| grep -A1 "Subject Alternative Name" | sed 's/^/ /'
|
||||||
|
|
||||||
|
if [ "$days" -lt "$WARN_DAYS" ]; then
|
||||||
|
echo "警告:剩余 $days 天,低于阈值 $WARN_DAYS 天" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "证书状态正常"
|
||||||
10
acme/crontab.example
Normal file
10
acme/crontab.example
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# acme.sh 安装时会自动写入一条 cron(每天执行 ~/.acme.sh/acme.sh --cron),
|
||||||
|
# 续签成功后自动执行 --reloadcmd,所以续签本身不需要再配 cron。
|
||||||
|
#
|
||||||
|
# 这里只需要一个"有效期检查"作为兜底告警:
|
||||||
|
# 自动续签可能静默失败,剩余天数低于 20 天时脚本以非 0 退出。
|
||||||
|
|
||||||
|
0 8 * * * bash /home/awei/workspace/common-server-public/acme/check-cert.sh >> /var/log/acme-check.log 2>&1
|
||||||
|
|
||||||
|
# 如需强制每天显式跑一次续签(一般不必),可加:
|
||||||
|
# 0 3 * * * bash /home/awei/workspace/common-server-public/acme/renew.sh >> /var/log/acme-renew.log 2>&1
|
||||||
25
acme/install.sh
Normal file
25
acme/install.sh
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# 安装 acme.sh(纯 Shell ACME 客户端,不依赖 Python / 容器 / snap)
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EMAIL="${EMAIL:-admin@stonelan.cn}"
|
||||||
|
ACME="${ACME:-$HOME/.acme.sh/acme.sh}"
|
||||||
|
|
||||||
|
if [ -s "$ACME" ]; then
|
||||||
|
echo "acme.sh 已安装:$ACME"
|
||||||
|
else
|
||||||
|
echo "==> 安装 acme.sh"
|
||||||
|
curl https://get.acme.sh | sh -s email="$EMAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# acme.sh 3.x 默认 CA 是 ZeroSSL,这里显式固定为 Let's Encrypt
|
||||||
|
"$ACME" --set-default-ca --server letsencrypt
|
||||||
|
|
||||||
|
echo "==> acme.sh 就绪"
|
||||||
|
"$ACME" --version
|
||||||
|
|
||||||
|
# 安装脚本会自动写入一条 cron(每天执行 acme.sh --cron),无需再手配续签
|
||||||
|
echo "==> 已注册的 cron:"
|
||||||
|
crontab -l 2>/dev/null | grep acme.sh || echo " (未找到,请手动添加,参考 crontab.example)"
|
||||||
61
acme/issue.sh
Normal file
61
acme/issue.sh
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# 首次申请证书并启用 HTTPS(完整引导)。
|
||||||
|
#
|
||||||
|
# 1. 准备宿主机目录:acme.sh 写挑战文件,nginx 容器 bind mount 只读
|
||||||
|
# 2. 启动 nginx —— 此时 ssl.d/ 为空,只加载 80 端口配置,不依赖证书
|
||||||
|
# 3. 申请 SAN 证书(webroot 验证,挑战文件由 nginx 直接对外提供)
|
||||||
|
# 4. 把证书安装到 /etc/letsencrypt/live/<CERT_NAME>/
|
||||||
|
# --reloadcmd 会被 acme.sh 记住,之后每次自动续签都执行
|
||||||
|
# 5. 启用 HTTPS server 块并重载 nginx
|
||||||
|
#
|
||||||
|
# 需要 root 权限(要写 /etc/letsencrypt 与 /var/www):sudo bash issue.sh
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
NGINX_DIR="$SCRIPT_DIR/../nginx"
|
||||||
|
|
||||||
|
EMAIL="${EMAIL:-admin@stonelan.cn}"
|
||||||
|
CERT_NAME="${CERT_NAME:-stonelan.cn}"
|
||||||
|
WEBROOT="${WEBROOT:-/var/www/certbot}"
|
||||||
|
CERT_HOME="${CERT_HOME:-/etc/letsencrypt/live/$CERT_NAME}"
|
||||||
|
DOMAINS="${DOMAINS:-fastgpt.stonelan.cn gitea.stonelan.cn image.stonelan.cn registry.stonelan.cn www.stonelan.cn}"
|
||||||
|
ACME="${ACME:-$HOME/.acme.sh/acme.sh}"
|
||||||
|
|
||||||
|
# acme.sh 的 Main_Domain 就是 -d 列表的第一个,--install-cert 要用它
|
||||||
|
PRIMARY="${DOMAINS%% *}"
|
||||||
|
|
||||||
|
if [ ! -s "$ACME" ]; then
|
||||||
|
echo "未找到 acme.sh,请先执行:$SCRIPT_DIR/install.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1. 目录
|
||||||
|
mkdir -p "$WEBROOT/.well-known/acme-challenge" "$CERT_HOME"
|
||||||
|
chmod 755 "$WEBROOT" "$WEBROOT/.well-known" "$WEBROOT/.well-known/acme-challenge"
|
||||||
|
|
||||||
|
# 2. nginx(无证书也能起来)
|
||||||
|
echo "==> 启动 nginx"
|
||||||
|
docker compose -f "$NGINX_DIR/docker-compose.yml" up -d
|
||||||
|
|
||||||
|
# 3. 申请
|
||||||
|
args=()
|
||||||
|
for d in $DOMAINS; do
|
||||||
|
args+=(-d "$d")
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "==> 申请证书(主域 $PRIMARY,共 $(echo $DOMAINS | wc -w) 个域名):$DOMAINS"
|
||||||
|
"$ACME" --issue --webroot "$WEBROOT" --server letsencrypt "${args[@]}"
|
||||||
|
|
||||||
|
# 4. 安装证书
|
||||||
|
echo "==> 安装证书到 $CERT_HOME"
|
||||||
|
"$ACME" --install-cert -d "$PRIMARY" \
|
||||||
|
--cert-file "$CERT_HOME/cert.pem" \
|
||||||
|
--key-file "$CERT_HOME/privkey.pem" \
|
||||||
|
--fullchain-file "$CERT_HOME/fullchain.pem" \
|
||||||
|
--reloadcmd "docker kill -s HUP nginx-proxy"
|
||||||
|
|
||||||
|
# 5. 启用 HTTPS
|
||||||
|
echo "==> 启用 HTTPS 配置"
|
||||||
|
exec bash "$NGINX_DIR/enable-ssl.sh"
|
||||||
20
acme/renew.sh
Normal file
20
acme/renew.sh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# 手动触发一次续签检查。
|
||||||
|
#
|
||||||
|
# acme.sh 安装时已经自动写入了 cron(每天 ~/.acme.sh/acme.sh --cron),
|
||||||
|
# 正常情况下不需要手动执行,这个脚本只是方便排查和立即验证。
|
||||||
|
# 续签成功时 acme.sh 会自动执行 issue.sh 里登记的 --reloadcmd。
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ACME="${ACME:-$HOME/.acme.sh/acme.sh}"
|
||||||
|
|
||||||
|
if [ ! -s "$ACME" ]; then
|
||||||
|
echo "未找到 acme.sh,请先执行本目录下的 install.sh" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始续签检查"
|
||||||
|
"$ACME" --cron
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 续签检查完成"
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 定义变量
|
|
||||||
DOMAIN="registry.deepseak.icu" # 主域名
|
|
||||||
ADDITIONAL_DOMAINS=("active.deepseak.icu" "bbs.deepseak.icu" "image.deepseak.icu" "gitea.deepseak.icu") # 额外域名
|
|
||||||
EMAIL="hpuzhagnwei@163.com" # 请替换为你的邮箱地址
|
|
||||||
|
|
||||||
# 检查 Certbot 是否安装
|
|
||||||
if ! command -v certbot &> /dev/null
|
|
||||||
then
|
|
||||||
echo "Certbot 未安装,开始安装..."
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y certbot python3-certbot-nginx
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 申请证书
|
|
||||||
echo "开始申请证书..."
|
|
||||||
|
|
||||||
# 构建域名参数
|
|
||||||
DOMAIN_ARGS="-d $DOMAIN"
|
|
||||||
for domain in "${ADDITIONAL_DOMAINS[@]}"; do
|
|
||||||
DOMAIN_ARGS="$DOMAIN_ARGS -d $domain"
|
|
||||||
done
|
|
||||||
|
|
||||||
sudo certbot certonly --nginx $DOMAIN_ARGS --email $EMAIL --agree-tos --no-eff-email
|
|
||||||
|
|
||||||
# 检查证书是否申请成功
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "证书申请成功!"
|
|
||||||
else
|
|
||||||
echo "证书申请失败,请检查错误信息。"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 安装自动续期任务
|
|
||||||
# echo "安装自动续期任务..."
|
|
||||||
# (crontab -l 2>/dev/null; echo "0 12 * * * /usr/bin/certbot renew --quiet") | crontab -
|
|
||||||
|
|
||||||
# echo "自动续期任务安装成功!"
|
|
||||||
3
csp-task.md
Normal file
3
csp-task.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
1. nginx配置有更改,构建新的镜像 ,
|
||||||
|
2. scp部署到100.66.1.5 这个机器上 用户名admin 密码 admin123
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
# Dolibarr ERP/CRM Docker部署指南
|
|
||||||
|
|
||||||
本指南将帮助您使用Docker Compose快速部署Dolibarr ERP/CRM系统。
|
|
||||||
|
|
||||||
## 功能特点
|
|
||||||
|
|
||||||
- 使用官方Dolibarr Docker镜像
|
|
||||||
- 集成MariaDB数据库
|
|
||||||
- 数据持久化存储
|
|
||||||
- 可自定义配置
|
|
||||||
|
|
||||||
## 系统要求
|
|
||||||
|
|
||||||
- Docker 18.06.0+
|
|
||||||
- Docker Compose 1.22.0+
|
|
||||||
|
|
||||||
## 部署步骤
|
|
||||||
|
|
||||||
### 1. 克隆或下载配置文件
|
|
||||||
|
|
||||||
确保您已经在`dolibarr`目录下有`docker-compose.yml`文件。
|
|
||||||
|
|
||||||
### 2. 启动服务
|
|
||||||
|
|
||||||
在`dolibarr`目录下执行以下命令:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
这将启动两个容器:
|
|
||||||
- `dolibarr`:Dolibarr ERP/CRM应用
|
|
||||||
- `dolibarr_db`:MariaDB数据库
|
|
||||||
|
|
||||||
### 3. 访问Dolibarr
|
|
||||||
|
|
||||||
启动完成后,通过以下地址访问Dolibarr:
|
|
||||||
|
|
||||||
```
|
|
||||||
http://localhost:8080
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 完成安装
|
|
||||||
|
|
||||||
首次访问时,您需要完成Dolibarr的安装配置:
|
|
||||||
|
|
||||||
1. 选择您的语言并点击"开始安装"
|
|
||||||
2. 检查系统需求(应该都是绿色的)
|
|
||||||
3. 数据库配置:
|
|
||||||
- 数据库类型:MySQL
|
|
||||||
- 数据库服务器:db
|
|
||||||
- 数据库名称:dolibarr
|
|
||||||
- 数据库用户:dolibarr
|
|
||||||
- 数据库密码:dolibarr_password
|
|
||||||
4. 点击"测试连接"并确认连接成功
|
|
||||||
5. 完成剩余的安装步骤
|
|
||||||
|
|
||||||
## 配置说明
|
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
|
|
||||||
在`docker-compose.yml`文件中,您可以修改以下环境变量:
|
|
||||||
|
|
||||||
- `DOLI_ADMIN_LOGIN`:Dolibarr管理员用户名(默认:admin)
|
|
||||||
- `DOLI_ADMIN_PASSWORD`:Dolibarr管理员密码(默认:admin_password)
|
|
||||||
- `DOLI_URL_ROOT`:Dolibarr访问URL(默认:http://localhost:8080)
|
|
||||||
- `MYSQL_ROOT_PASSWORD`:MariaDB root用户密码(默认:root_password)
|
|
||||||
- `MYSQL_DATABASE`:数据库名称(默认:dolibarr)
|
|
||||||
- `MYSQL_USER`:数据库用户名(默认:dolibarr)
|
|
||||||
- `MYSQL_PASSWORD`:数据库密码(默认:dolibarr_password)
|
|
||||||
|
|
||||||
### 端口映射
|
|
||||||
|
|
||||||
默认将Dolibarr的80端口映射到主机的8080端口。您可以通过修改`ports`部分来更改:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
ports:
|
|
||||||
- "您选择的端口:80"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 数据持久化
|
|
||||||
|
|
||||||
使用Docker卷来持久化存储数据:
|
|
||||||
- `dolibarr_html`:存储Dolibarr应用文件
|
|
||||||
- `dolibarr_documents`:存储Dolibarr文档和上传文件
|
|
||||||
- `dolibarr_db`:存储MariaDB数据库数据
|
|
||||||
|
|
||||||
## 管理命令
|
|
||||||
|
|
||||||
### 查看日志
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 查看Dolibarr日志
|
|
||||||
docker-compose logs dolibarr
|
|
||||||
|
|
||||||
# 查看数据库日志
|
|
||||||
docker-compose logs db
|
|
||||||
|
|
||||||
# 查看所有日志
|
|
||||||
docker-compose logs
|
|
||||||
```
|
|
||||||
|
|
||||||
### 停止服务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
### 重启服务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose restart
|
|
||||||
```
|
|
||||||
|
|
||||||
### 更新服务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 拉取最新镜像
|
|
||||||
docker-compose pull
|
|
||||||
|
|
||||||
# 重新启动服务
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## 安全建议
|
|
||||||
|
|
||||||
1. 生产环境中请修改默认密码
|
|
||||||
2. 考虑使用HTTPS协议访问
|
|
||||||
3. 定期备份数据卷
|
|
||||||
4. 限制容器的网络访问
|
|
||||||
|
|
||||||
## 常见问题
|
|
||||||
|
|
||||||
### Q: 无法访问Dolibarr?
|
|
||||||
A: 检查容器是否正在运行,端口是否正确映射,以及防火墙设置。
|
|
||||||
|
|
||||||
### Q: 忘记管理员密码?
|
|
||||||
A: 您可以通过修改数据库中的`llx_user`表来重置密码,或者在环境变量中重新设置`DOLI_ADMIN_PASSWORD`并重启容器。
|
|
||||||
|
|
||||||
### Q: 如何备份数据?
|
|
||||||
A: 您可以使用`docker cp`命令将数据卷中的内容复制到本地:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker cp dolibarr:/var/www/html ./backup/html
|
|
||||||
docker cp dolibarr:/var/www/documents ./backup/documents
|
|
||||||
docker exec dolibarr_db mysqldump -u root -proot_password dolibarr > ./backup/dolibarr.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
## 联系方式
|
|
||||||
|
|
||||||
如有问题,请参考[Dolibarr官方文档](https://wiki.dolibarr.org/index.php/Main_Page)或[Docker Hub页面](https://hub.docker.com/r/dolibarr/dolibarr/)。
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
version: '3.7'
|
|
||||||
|
|
||||||
services:
|
|
||||||
# Dolibarr ERP/CRM
|
|
||||||
dolibarr:
|
|
||||||
image: dolibarr/dolibarr:latest
|
|
||||||
container_name: dolibarr
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
environment:
|
|
||||||
- DOLI_DB_HOST=db
|
|
||||||
- DOLI_DB_USER=dolibarr
|
|
||||||
- DOLI_DB_PASSWORD=dolibarr_password
|
|
||||||
- DOLI_DB_NAME=dolibarr
|
|
||||||
- DOLI_ADMIN_LOGIN=admin
|
|
||||||
- DOLI_ADMIN_PASSWORD=admin_password
|
|
||||||
- DOLI_URL_ROOT=http://localhost:8080
|
|
||||||
volumes:
|
|
||||||
- dolibarr_html:/var/www/html
|
|
||||||
- dolibarr_documents:/var/www/documents
|
|
||||||
|
|
||||||
# MariaDB Database
|
|
||||||
db:
|
|
||||||
image: mariadb:10.6
|
|
||||||
container_name: dolibarr_db
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
- MYSQL_ROOT_PASSWORD=root_password
|
|
||||||
- MYSQL_DATABASE=dolibarr
|
|
||||||
- MYSQL_USER=dolibarr
|
|
||||||
- MYSQL_PASSWORD=dolibarr_password
|
|
||||||
volumes:
|
|
||||||
- dolibarr_db:/var/lib/mysql
|
|
||||||
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
dolibarr_html:
|
|
||||||
dolibarr_documents:
|
|
||||||
dolibarr_db:
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
frpc:
|
frpc:
|
||||||
image: frpc-client:latest
|
image: frpc-client:09051708
|
||||||
container_name: frpc-client
|
container_name: frpc-client
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
265663
frpc-client/frp.tar.gz.b64
265663
frpc-client/frp.tar.gz.b64
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
# frpc 基础配置
|
# frpc 基础配置
|
||||||
serverAddr = "47.239.121.24"
|
serverAddr = "47.113.230.48"
|
||||||
serverPort = 7000
|
serverPort = 7000
|
||||||
auth.method = "token"
|
auth.method = "token"
|
||||||
auth.token = "8f3c9b7d5e2a4f6h1i0j"
|
auth.token = "8f3c9b7d5e2a4f6h1i0j"
|
||||||
@@ -14,34 +14,6 @@ remotePort = 80
|
|||||||
[[proxies]]
|
[[proxies]]
|
||||||
name = "https"
|
name = "https"
|
||||||
type = "tcp"
|
type = "tcp"
|
||||||
localIP = "10.0.3.148"
|
localIP = "nginx-proxy"
|
||||||
localPort = 4430
|
localPort = 8443
|
||||||
remotePort = 443
|
remotePort = 443
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,29 @@
|
|||||||
# Nginx Docker image
|
# 使用官方 Nginx 镜像
|
||||||
# 包含自定义配置的反向代理
|
FROM nginx:09051708
|
||||||
|
|
||||||
FROM nginx:alpine
|
# 维护者信息
|
||||||
|
LABEL maintainer="awei"
|
||||||
|
LABEL description="HTTP server with SSL support"
|
||||||
|
|
||||||
LABEL maintainer="StoneLan"
|
# 复制配置文件
|
||||||
LABEL description="Nginx reverse proxy container"
|
# 先清理基础镜像中可能残留的旧配置,再写入新配置
|
||||||
|
# conf.d 只放不依赖证书的常驻配置(80 端口:ACME 验证 + HTTPS 跳转)
|
||||||
# 复制 nginx 配置
|
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
RUN rm -rf /etc/nginx/conf.d/*
|
||||||
COPY conf.d /etc/nginx/conf.d
|
COPY conf.d /etc/nginx/conf.d
|
||||||
|
COPY verification.html /usr/share/nginx/html/verification.html
|
||||||
|
|
||||||
# 创建必要的目录
|
# 创建日志目录与 HTTPS 配置目录
|
||||||
RUN mkdir -p /var/log/nginx && \
|
# ssl.d 必须存在:nginx.conf 里的 wildcard include 在目录不存在时会报 emerg
|
||||||
mkdir -p /etc/nginx/ssl && \
|
RUN mkdir -p /var/log/nginx /etc/nginx/ssl.d
|
||||||
chown -R nginx:nginx /var/log/nginx && \
|
|
||||||
chown -R nginx:nginx /etc/nginx
|
|
||||||
|
|
||||||
EXPOSE 80 443
|
# 暴露端口
|
||||||
|
EXPOSE 80
|
||||||
|
EXPOSE 8443
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
# 健康检查:/healthz 固定返回 200,不跟随 301,冷启动阶段也不会误判
|
||||||
CMD wget --no-verbose --tries=1 --spider http://localhost/health || exit 1
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --quiet --tries=1 -O /dev/null http://127.0.0.1/healthz || exit 1
|
||||||
|
|
||||||
|
# 启动 Nginx
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|||||||
30
nginx/conf.d/00-http.conf
Normal file
30
nginx/conf.d/00-http.conf
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# HTTP 入口:ACME 验证 + HTTPS 跳转
|
||||||
|
#
|
||||||
|
# 【关键】这个文件必须常驻,且不能引用任何证书文件。
|
||||||
|
# 首次部署时证书尚不存在,如果 nginx 加载了带 ssl_certificate 的 server 块,
|
||||||
|
# 会直接 [emerg] cannot load certificate 退出;而申请证书又必须要有 80 端口可用
|
||||||
|
# —— 形成死锁。因此所有 HTTPS server 块统一放到 /etc/nginx/ssl.d/,
|
||||||
|
# 由 nginx/enable-ssl.sh 在证书就绪后再启用。
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# 健康检查探针(容器 HEALTHCHECK 使用),不跟随 301
|
||||||
|
location = /healthz {
|
||||||
|
access_log off;
|
||||||
|
default_type text/plain;
|
||||||
|
return 200 "ok\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# ACME HTTP-01 验证
|
||||||
|
# acme.sh 通过 webroot 写入 /var/www/certbot/.well-known/acme-challenge/<token>
|
||||||
|
# 这是宿主机目录,nginx 容器以只读方式 bind mount
|
||||||
|
location /.well-known/acme-challenge/ {
|
||||||
|
root /var/www/certbot;
|
||||||
|
default_type text/plain;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name gitea.membank.xyz;
|
|
||||||
client_max_body_size 200m;
|
|
||||||
location / {
|
|
||||||
proxy_pass http://gitea:3000;
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name image.membank.xyz;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://10.0.3.14:3004;
|
|
||||||
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;
|
|
||||||
|
|
||||||
# 添加代理超时配置
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name membank.membank.xyz;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://10.0.3.148:3000;
|
|
||||||
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;
|
|
||||||
|
|
||||||
# 添加代理超时配置
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
}
|
|
||||||
location /bbs-go {
|
|
||||||
proxy_pass http://10.0.3.148:9000;
|
|
||||||
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;
|
|
||||||
|
|
||||||
# 添加代理超时配置
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name navidrome.membank.xyz;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://127.0.0.1:4533;
|
|
||||||
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;
|
|
||||||
|
|
||||||
# 添加代理超时配置
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
|
|
||||||
# 针对Navidrome的特殊配置
|
|
||||||
# 支持大文件上传和流媒体传输
|
|
||||||
client_max_body_size 100M;
|
|
||||||
proxy_buffering off;
|
|
||||||
|
|
||||||
# 启用gzip压缩
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_min_length 1024;
|
|
||||||
gzip_proxied any;
|
|
||||||
gzip_comp_level 6;
|
|
||||||
gzip_types
|
|
||||||
text/plain
|
|
||||||
text/css
|
|
||||||
text/xml
|
|
||||||
text/javascript
|
|
||||||
application/json
|
|
||||||
application/javascript
|
|
||||||
application/xml+rss
|
|
||||||
application/atom+xml
|
|
||||||
image/svg+xml;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name registry.membank.xyz;
|
|
||||||
client_max_body_size 500m;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://127.0.0.1:3005;
|
|
||||||
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;
|
|
||||||
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,21 @@
|
|||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:09051708
|
||||||
container_name: nginx-proxy
|
container_name: nginx-proxy
|
||||||
ports:
|
ports:
|
||||||
- "8081:80"
|
- "8081:80"
|
||||||
- "4430:443"
|
- "8443:8443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./conf.d:/etc/nginx/conf.d:ro
|
# 证书:宿主机 acme.sh 写入,nginx 只读
|
||||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||||
|
# ACME HTTP-01 挑战文件:宿主机 acme.sh 写入,nginx 只读
|
||||||
|
- /var/www/certbot:/var/www/certbot:ro
|
||||||
|
# HTTPS server 块:默认为空,证书就绪后由 enable-ssl.sh 写入
|
||||||
|
- ./ssl.d:/etc/nginx/ssl.d:ro
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- trim-default
|
- trim-default
|
||||||
|
|
||||||
|
networks:
|
||||||
|
trim-default:
|
||||||
|
external: true
|
||||||
|
|||||||
59
nginx/enable-ssl.sh
Normal file
59
nginx/enable-ssl.sh
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# 启用 HTTPS 配置:证书就绪后,把 ssl.d.available/ 下的 server 块
|
||||||
|
# 复制进 ssl.d/(nginx 容器 bind mount 并 include 的目录),校验后优雅重载 nginx。
|
||||||
|
#
|
||||||
|
# 冷启动时 ssl.d/ 为空,nginx 只加载 conf.d/00-http.conf(不引用证书),
|
||||||
|
# 因此可以在没有证书的情况下启动并提供 80 端口 —— 这是打破
|
||||||
|
# "先有证书还是先有 nginx" 死锁的关键。
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
AVAILABLE="$SCRIPT_DIR/ssl.d.available"
|
||||||
|
ENABLED="$SCRIPT_DIR/ssl.d"
|
||||||
|
|
||||||
|
CERT_NAME="${CERT_NAME:-stonelan.cn}"
|
||||||
|
CERT_FULL="/etc/letsencrypt/live/$CERT_NAME/fullchain.pem"
|
||||||
|
DOMAINS="${DOMAINS:-fastgpt.stonelan.cn gitea.stonelan.cn image.stonelan.cn registry.stonelan.cn www.stonelan.cn}"
|
||||||
|
|
||||||
|
# 证书在宿主机上,直接判断即可(不再需要进容器)
|
||||||
|
if [ ! -f "$CERT_FULL" ]; then
|
||||||
|
echo "证书尚未生成:$CERT_FULL"
|
||||||
|
echo "请先执行 acme/issue.sh,成功后再运行本脚本"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$ENABLED"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
copied=()
|
||||||
|
for d in $DOMAINS; do
|
||||||
|
conf="$AVAILABLE/$d.conf"
|
||||||
|
if [ ! -f "$conf" ]; then
|
||||||
|
echo "跳过 $d:缺少 $conf"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! cmp -s "$conf" "$ENABLED/$d.conf" 2>/dev/null; then
|
||||||
|
cp "$conf" "$ENABLED/$d.conf"
|
||||||
|
copied+=("$ENABLED/$d.conf")
|
||||||
|
echo "已启用 $d"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${#copied[@]}" -eq 0 ]; then
|
||||||
|
echo "HTTPS 配置已是最新,无需变更"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if out=$(docker compose exec -T nginx-proxy nginx -t 2>&1); then
|
||||||
|
echo "$out" | sed 's/^/ /'
|
||||||
|
docker kill -s HUP nginx-proxy
|
||||||
|
echo "nginx 已重载,HTTPS 配置生效"
|
||||||
|
else
|
||||||
|
echo "$out" | sed 's/^/ /'
|
||||||
|
echo "nginx 配置校验失败,回滚本次变更" >&2
|
||||||
|
rm -f "${copied[@]}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -25,5 +25,10 @@ http {
|
|||||||
|
|
||||||
keepalive_timeout 65;
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
# HTTPS server 块按需加载:
|
||||||
|
# 该目录默认为空(nginx 的 wildcard include 匹配 0 个文件时不报错),
|
||||||
|
# 证书申请成功后由 enable-ssl.sh 写入配置,从而避免冷启动时
|
||||||
|
# 因证书文件不存在导致 nginx 拒绝启动。
|
||||||
|
include /etc/nginx/ssl.d/*.conf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,35 @@
|
|||||||
|
# HTTPS 配置 —— fastgpt.stonelan.cn
|
||||||
|
# 5 个域名共用一张 SAN 证书,统一放在 /etc/letsencrypt/live/stonelan.cn/。
|
||||||
|
# 由 nginx/enable-ssl.sh 在证书就绪后复制到 ssl.d/ 才会被 nginx 加载。
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 8443 ssl;
|
||||||
server_name fastgpt.membank.xyz;
|
server_name fastgpt.stonelan.cn;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/stonelan.cn/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/stonelan.cn/privkey.pem;
|
||||||
|
|
||||||
|
# SSL 优化配置
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://10.0.3.14:3000;
|
proxy_pass http://10.0.3.173:3000;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
# 添加代理超时配置
|
|
||||||
proxy_connect_timeout 60s;
|
proxy_connect_timeout 60s;
|
||||||
proxy_read_timeout 600s;
|
proxy_read_timeout 600s;
|
||||||
proxy_send_timeout 600s;
|
proxy_send_timeout 600s;
|
||||||
|
|
||||||
# 支持大文件上传和API请求
|
|
||||||
client_max_body_size 100M;
|
client_max_body_size 100M;
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
|
|
||||||
# 启用gzip压缩
|
|
||||||
gzip on;
|
gzip on;
|
||||||
gzip_vary on;
|
gzip_vary on;
|
||||||
gzip_min_length 1024;
|
gzip_min_length 1024;
|
||||||
30
nginx/ssl.d.available/gitea.conf
Normal file
30
nginx/ssl.d.available/gitea.conf
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# HTTPS 配置 —— gitea.stonelan.cn
|
||||||
|
# 5 个域名共用一张 SAN 证书,统一放在 /etc/letsencrypt/live/stonelan.cn/。
|
||||||
|
# 由 nginx/enable-ssl.sh 在证书就绪后复制到 ssl.d/ 才会生效。
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
server_name gitea.stonelan.cn;
|
||||||
|
client_max_body_size 200m;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/stonelan.cn/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/stonelan.cn/privkey.pem;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://gitea:3000;
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
nginx/ssl.d.available/image.conf
Normal file
29
nginx/ssl.d.available/image.conf
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# HTTPS 配置 —— image.stonelan.cn
|
||||||
|
# 5 个域名共用一张 SAN 证书,统一放在 /etc/letsencrypt/live/stonelan.cn/。
|
||||||
|
# 由 nginx/enable-ssl.sh 在证书就绪后复制到 ssl.d/ 才会生效。
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
server_name image.stonelan.cn;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/stonelan.cn/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/stonelan.cn/privkey.pem;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://10.0.3.173:3004;
|
||||||
|
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;
|
||||||
|
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
nginx/ssl.d.available/registry.conf
Normal file
30
nginx/ssl.d.available/registry.conf
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# HTTPS 配置 —— registry.stonelan.cn
|
||||||
|
# 5 个域名共用一张 SAN 证书,统一放在 /etc/letsencrypt/live/stonelan.cn/。
|
||||||
|
# 由 nginx/enable-ssl.sh 在证书就绪后复制到 ssl.d/ 才会生效。
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
server_name registry.stonelan.cn;
|
||||||
|
client_max_body_size 500m;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/stonelan.cn/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/stonelan.cn/privkey.pem;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:3005;
|
||||||
|
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;
|
||||||
|
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
nginx/ssl.d.available/www.conf
Normal file
29
nginx/ssl.d.available/www.conf
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# HTTPS 配置 —— www.stonelan.cn
|
||||||
|
# 5 个域名共用一张 SAN 证书,统一放在 /etc/letsencrypt/live/stonelan.cn/。
|
||||||
|
# 由 nginx/enable-ssl.sh 在证书就绪后复制到 ssl.d/ 才会生效。
|
||||||
|
server {
|
||||||
|
listen 8443 ssl;
|
||||||
|
server_name www.stonelan.cn;
|
||||||
|
|
||||||
|
ssl_certificate /etc/letsencrypt/live/stonelan.cn/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/stonelan.cn/privkey.pem;
|
||||||
|
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://10.0.3.173:8080;
|
||||||
|
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;
|
||||||
|
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
nginx/ssl.d/.gitkeep
Normal file
2
nginx/ssl.d/.gitkeep
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# nginx 从这里加载 HTTPS 配置(wildcard include,目录为空时 nginx 正常启动)。
|
||||||
|
# 首次申请证书前本目录为空,由 ../enable-ssl.sh 按需写入。
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# 把仓库里的 nginx 配置同步到宿主机 nginx(非容器部署路径)。
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
# 检查并创建nginx用户
|
# 检查并创建nginx用户
|
||||||
if ! id -u nginx >/dev/null 2>&1; then
|
if ! id -u nginx >/dev/null 2>&1; then
|
||||||
@@ -6,31 +10,55 @@ if ! id -u nginx >/dev/null 2>&1; then
|
|||||||
sudo useradd -r -s /sbin/nologin nginx
|
sudo useradd -r -s /sbin/nologin nginx
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 创建 conf.d 目录(如果不存在)
|
# 创建配置目录(ssl.d 必须存在,nginx.conf 里的 wildcard include 在目录缺失时会报 emerg)
|
||||||
sudo mkdir -p /etc/nginx/conf.d
|
sudo mkdir -p /etc/nginx/conf.d /etc/nginx/ssl.d
|
||||||
|
|
||||||
# 备份并覆盖 nginx.conf 文件
|
# 备份并覆盖 nginx.conf 文件
|
||||||
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
|
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
|
||||||
sudo cp nginx.conf /etc/nginx/
|
sudo cp nginx.conf /etc/nginx/
|
||||||
|
|
||||||
# 备份并覆盖 conf.d 目录下的所有 .conf 文件
|
# 备份并覆盖 conf.d 目录下的所有 .conf 文件(只放不依赖证书的配置)
|
||||||
for conf in conf.d/*.conf; do
|
for conf in conf.d/*.conf; do
|
||||||
filename=$(basename "$conf")
|
filename=$(basename "$conf")
|
||||||
sudo cp "/etc/nginx/conf.d/$filename" "/etc/nginx/conf.d/${filename}.bak" 2>/dev/null || true
|
sudo cp "/etc/nginx/conf.d/$filename" "/etc/nginx/conf.d/${filename}.bak" 2>/dev/null || true
|
||||||
sudo cp "$conf" /etc/nginx/conf.d/
|
sudo cp "$conf" /etc/nginx/conf.d/
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# HTTPS 配置:证书就绪后才启用,避免 nginx 因证书缺失拒绝启动
|
||||||
|
# 5 个域名共用一张 SAN 证书,统一放在 CERT_NAME 目录下
|
||||||
|
CERT_NAME="${CERT_NAME:-stonelan.cn}"
|
||||||
|
CERT_FULL="/etc/letsencrypt/live/$CERT_NAME/fullchain.pem"
|
||||||
|
DOMAINS="${DOMAINS:-fastgpt.stonelan.cn gitea.stonelan.cn image.stonelan.cn registry.stonelan.cn www.stonelan.cn}"
|
||||||
|
|
||||||
|
if [ -f "$CERT_FULL" ]; then
|
||||||
|
for d in $DOMAINS; do
|
||||||
|
src="ssl.d.available/$d.conf"
|
||||||
|
if [ -f "$src" ]; then
|
||||||
|
sudo cp "$src" "/etc/nginx/ssl.d/$d.conf"
|
||||||
|
echo "已启用 $d"
|
||||||
|
else
|
||||||
|
echo "跳过 $d:缺少 $src"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "证书尚未生成($CERT_FULL),跳过 HTTPS 配置"
|
||||||
|
fi
|
||||||
|
|
||||||
# 测试并重载配置
|
# 测试并重载配置
|
||||||
if sudo nginx -t; then
|
if sudo nginx -t; then
|
||||||
|
if sudo systemctl is-active --quiet nginx; then
|
||||||
sudo systemctl reload nginx
|
sudo systemctl reload nginx
|
||||||
echo "配置已生效,HTTPS已启用"
|
echo "配置已重载"
|
||||||
|
else
|
||||||
|
sudo systemctl start nginx
|
||||||
|
echo "nginx 已启动"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "配置测试失败,已恢复备份"
|
echo "配置测试失败,已恢复备份"
|
||||||
# 恢复 nginx.conf 备份
|
|
||||||
sudo cp /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf
|
sudo cp /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf
|
||||||
# 恢复 conf.d 目录下的所有 .conf 文件备份
|
|
||||||
for conf in conf.d/*.conf; do
|
for conf in conf.d/*.conf; do
|
||||||
filename=$(basename "$conf")
|
filename=$(basename "$conf")
|
||||||
sudo mv -f "/etc/nginx/conf.d/${filename}.bak" "/etc/nginx/conf.d/$filename" 2>/dev/null || true
|
sudo mv -f "/etc/nginx/conf.d/${filename}.bak" "/etc/nginx/conf.d/$filename" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
1
nginx/verification.html
Normal file
1
nginx/verification.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
verify_01965aad87b3aae1c15f4373ae9efcfb
|
||||||
Reference in New Issue
Block a user