0514.2
This commit is contained in:
parent
d972f9b3dc
commit
a8696e41fc
104
.github/workflows/ci-cd.yml
vendored
Normal file
104
.github/workflows/ci-cd.yml
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
name: 部署 Next.js 站点到 Gitea
|
||||||
|
|
||||||
|
# 定义触发工作流程的条件
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
# 当推送到 "main" 分支时触发工作流程
|
||||||
|
branches: ["main"]
|
||||||
|
# 手动触发工作流程
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
#permissions:
|
||||||
|
# contents: read
|
||||||
|
# pages: write
|
||||||
|
# id-token: write
|
||||||
|
|
||||||
|
# 设置工作流程中所需的权限
|
||||||
|
permissions:
|
||||||
|
# 只读权限用于读取仓库内容
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
#concurrency:
|
||||||
|
# group: "pages"
|
||||||
|
# cancel-in-progress: false
|
||||||
|
|
||||||
|
# 设置工作流的并发控制
|
||||||
|
concurrency:
|
||||||
|
group: "deploy" # 定义并发组名称为 "deploy"
|
||||||
|
cancel-in-progress: false # 不取消正在运行的工作流
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
# 指定在最新的 Ubuntu 环境下运行
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# 主要执行的步骤
|
||||||
|
steps:
|
||||||
|
# 第一步:检出(checkout)代码
|
||||||
|
- name: 检出代码
|
||||||
|
# 使用 GitHub 官方的 actions/checkout@v4
|
||||||
|
#uses: actions/checkout@v4
|
||||||
|
uses: https://git.aoun.ltd/actions/checkout@v4
|
||||||
|
|
||||||
|
# 第二步:将代码通过 SCP 传输到群晖服务器上
|
||||||
|
- name: 🚚 将项目文件复制到目标服务器
|
||||||
|
# 使用 appleboy 的 SCP 动作传输文件到远程服务器
|
||||||
|
#uses: appleboy/scp-action@v0.1.7
|
||||||
|
uses: https://git.aoun.ltd/298977887/scp-action@v0.1.7
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SYNOLOGY_HOST }}
|
||||||
|
username: ${{ secrets.SYNOLOGY_USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: ${{ secrets.SYNOLOGY_SSH_PORT }}
|
||||||
|
source: "."
|
||||||
|
target: "/volume2/docker/saas00001/"
|
||||||
|
|
||||||
|
- name: 🛠️ 在群晖上构建并运行Docker镜像
|
||||||
|
#uses: appleboy/ssh-action@master
|
||||||
|
# 使用 appleboy 的 SSH 动作来连接服务器并运行命令
|
||||||
|
#uses: appleboy/ssh-action@v1.0.3
|
||||||
|
#使用自定义的 SSH 动作
|
||||||
|
uses: https://git.aoun.ltd/298977887/ssh-action@v1.0.3
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SYNOLOGY_HOST }}
|
||||||
|
username: ${{ secrets.SYNOLOGY_USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
port: ${{ secrets.SYNOLOGY_SSH_PORT }}
|
||||||
|
script: |
|
||||||
|
# 通过 set -e 使脚本在遇到错误时立即停止
|
||||||
|
set -e
|
||||||
|
echo "🚀 开始执行部署..."
|
||||||
|
#cd /volume1/docker/saas01
|
||||||
|
cd /volume2/docker/saas01
|
||||||
|
echo "🔧 正在构建临时镜像..."
|
||||||
|
#/usr/local/bin/docker build -t saas01-temp .
|
||||||
|
if /usr/local/bin/docker build -t saas01-temp .; then
|
||||||
|
echo "✅ 镜像构建成功,开始更新容器..."
|
||||||
|
echo "🔧 正在停止旧容器..."
|
||||||
|
/usr/local/bin/docker stop saas01 || true
|
||||||
|
echo "🔧 正在删除旧容器..."
|
||||||
|
/usr/local/bin/docker rm saas01 || true
|
||||||
|
echo "🔧 正在删除旧镜像..."
|
||||||
|
/usr/local/bin/docker rmi saas01 || true
|
||||||
|
echo "🔧 重命名新镜像..."
|
||||||
|
/usr/local/bin/docker tag saas01-temp saas01
|
||||||
|
/usr/local/bin/docker rmi saas01-temp
|
||||||
|
echo "🚀 正在运行新容器..."
|
||||||
|
#/usr/local/bin/docker run -d -p 3300:3000 --name saas01 -e TZ=Asia/Shanghai saas01
|
||||||
|
# 启动新的容器,使用指定的环境变量和端口映射,并设置自动重启功能
|
||||||
|
# 容器名称为 saas01,镜像名称为 saas01
|
||||||
|
# 自动重启容器,除非手动停止
|
||||||
|
# 将本地 3300 端口映射到容器的 3000 端口
|
||||||
|
# 设置时区为上海
|
||||||
|
# 设置 API 地址,最后一行没有反斜杠
|
||||||
|
# 使用 saas01 镜像运行容器
|
||||||
|
/usr/local/bin/docker run -d \
|
||||||
|
--name saas01 \
|
||||||
|
--restart unless-stopped \
|
||||||
|
-p 3300:3000 \
|
||||||
|
-e TZ=Asia/Shanghai \
|
||||||
|
-e NEXT_PUBLIC_API=https://emoji.aoun.ltd/ \
|
||||||
|
saas01
|
||||||
|
echo "🎉 部署完成!"
|
||||||
|
else
|
||||||
|
echo "❌ 镜像构建失败!,保留旧容器运行。"
|
||||||
|
fi
|
67
docker-compose.production.yml
Normal file
67
docker-compose.production.yml
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Next.js 应用服务
|
||||||
|
nextjs-app:
|
||||||
|
image: ${DOCKER_IMAGE:-user/saas-app:latest}
|
||||||
|
container_name: nextjs-saas-app
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DB_HOST=${DB_HOST:-mysql}
|
||||||
|
- DB_USER=${DB_USER:-root}
|
||||||
|
- DB_PASSWORD=${DB_PASSWORD:-aiwoQwo520..}
|
||||||
|
- DB_NAME=${DB_NAME:-saas_db}
|
||||||
|
- DB_PORT=${DB_PORT:-3306}
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./uploads:/app/uploads
|
||||||
|
networks:
|
||||||
|
- saas-network
|
||||||
|
|
||||||
|
# MySQL 数据库服务
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: my-mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-aiwoQwo520..}
|
||||||
|
- MYSQL_DATABASE=${MYSQL_DATABASE:-saas_db}
|
||||||
|
- MYSQL_USER=${MYSQL_USER:-saas_user}
|
||||||
|
- MYSQL_PASSWORD=${MYSQL_PASSWORD:-saas_password}
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
- ./scripts:/docker-entrypoint-initdb.d
|
||||||
|
networks:
|
||||||
|
- saas-network
|
||||||
|
|
||||||
|
# Nginx 反向代理
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx-proxy
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/conf.d:/etc/nginx/conf.d
|
||||||
|
- ./nginx/ssl:/etc/nginx/ssl
|
||||||
|
- ./nginx/logs:/var/log/nginx
|
||||||
|
depends_on:
|
||||||
|
- nextjs-app
|
||||||
|
networks:
|
||||||
|
- saas-network
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# 定义持久化卷
|
||||||
|
volumes:
|
||||||
|
mysql_data:
|
||||||
|
|
||||||
|
# 定义网络
|
||||||
|
networks:
|
||||||
|
saas-network:
|
||||||
|
driver: bridge
|
86
nginx/conf.d/default.conf
Normal file
86
nginx/conf.d/default.conf
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
# 重定向HTTP请求到HTTPS
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
# SSL证书配置
|
||||||
|
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
# 安全相关的HTTP头
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff";
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
|
||||||
|
# 负载限制配置
|
||||||
|
client_max_body_size 100M;
|
||||||
|
client_body_buffer_size 128k;
|
||||||
|
|
||||||
|
# 代理缓存设置
|
||||||
|
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:10m inactive=7d use_temp_path=off;
|
||||||
|
proxy_cache_key "$scheme$request_method$host$request_uri";
|
||||||
|
|
||||||
|
# 静态资源处理
|
||||||
|
location /_next/static {
|
||||||
|
proxy_cache STATIC;
|
||||||
|
proxy_pass http://nextjs-app:3000/_next/static;
|
||||||
|
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;
|
||||||
|
|
||||||
|
# 缓存设置
|
||||||
|
expires 30d;
|
||||||
|
add_header Cache-Control "public, max-age=2592000, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
# 上传文件目录
|
||||||
|
location /uploads {
|
||||||
|
proxy_pass http://nextjs-app:3000/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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# API路由
|
||||||
|
location /api {
|
||||||
|
proxy_pass http://nextjs-app:3000/api;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
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_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 所有其他请求
|
||||||
|
location / {
|
||||||
|
proxy_pass http://nextjs-app:3000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
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_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user