[Vibe Coding][Act Runner]Gitea Actions

Gitea Actions是Gitea内置的CI&CD解决方案,它最大程度的兼容了Github Actions的设计语法和使用方式。

升级Gitea

从Gitea 1.19开始支持原生CI&CD的Actions解决方案,之前我安装的Gitea版本是1.20.5,升级到最新稳定版本Gitea 1.25.1,修改docker-compose.ymlimage即可:

1
2
3
4
5
6
7
8
9
10
11
12
services:
server:
image: gitea/gitea:1.25.1-rootless
restart: always
volumes:
- ./data:/var/lib/gitea
- ./config:/etc/gitea
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:2222"

如果需要重新创建,参考轻量级DevOps平台-Gitea

安装Act Runner

Act Runner是一个独立的程序,首先要注册Runner到Gitea实例中,然后Gitea Actions发送Job到Runner中运行。下载预构建的二进制文件,当前最新版本是act_runner-0.2.13后面章节使用docker容器创建自托管Runner服务)。

设置Runner

1
2
3
4
5
6
7
8
./act_runner register --no-interactive --instance <instance> --token <token>
#
$ ./act_runner-0.2.13-linux-arm64 register --no-interactive --instance http://xxx.xxx.xxx.xxx:3000 --token ZEHjxRucixxxxxxxxxxxxx
INFO Registering runner, arch=arm64, os=linux, version=v0.2.13.
WARN Runner in user-mode.
INFO Runner name is empty, use hostname 'LAPTOP-S3BIPLGN'.
DEBU Successfully pinged the Gitea instance server
INFO Runner registered successfully.

instance是您的Gitea实例的地址,如http://192.168.8.8:3000 或 https://gitea.com。 Runner和Job容器(由Runner启动以执行Job)将连接到此地址。 这意味着它可能与用于Web访问的ROOT_URL不同。 使用回环地址(例如127.0.0.1 或 localhost)是一个不好的选择。 如果不确定使用哪个地址,通常选择局域网地址即可。

token 用于身份验证和标识,例如P2U1U0oB4XaRCi8azcngmPCLbRpUGapalhmddh23。 它只能使用一次,并且不能用于注册多个Runner。 您可以从 <your_gitea.com>/admin/runners 获取令牌。

  • 注意一:注册Runner后能够自动生成一个.runner文件;
  • 注意二:每次删掉Gitea实例(docker-compose down)后重新创建容器(docker-compose up -d)都会生成新的token,此时需要重新注册。

启动Runner,就可以在Gitea管理页面上看到注册情况:

1
2
3
4
5
./act_runner daemon
#
$ ./act_runner-0.2.13-linux-arm64 daemon
INFO[2025-11-16T21:38:05+08:00] Starting runner daemon
INFO[2025-11-16T21:38:05+08:00] runner: LAPTOP-S3BIPLGN, with version: v0.2.13, with labels: [ubuntu-latest ubuntu-24.04 ubuntu-22.04], declare successfully

使用Actions

即使对于启用了Gitea实例的Actions,存储库仍默认禁用Actions。

要启用它,请转到存储库的设置页面,例如your_gitea.com/<owner>/repo/settings,然后启用Enable Repository Actions

docker-dompose

拉取最新稳定版本

1
2
3
4
5
6
7
8
9
$ docker pull gitea/act_runner:0.2.13
0.2.13: Pulling from gitea/act_runner
9824c27679d3: Pull complete
96e70a89510f: Pull complete
748572556419: Pull complete
7fd1ed8ea89d: Pull complete
Digest: sha256:8477d5b61b655caad4449888bae39f1f34bebd27db56cb15a62dccb3dcf3a944
Status: Downloaded newer image for gitea/act_runner:0.2.13
docker.io/gitea/act_runner:0.2.13

配置相关文件

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
$ mkdir act_runner & cd act_runner
$ docker run --entrypoint="" --rm -it gitea/act_runner:0.2.13 act_runner generate-config > config.yaml
$ mkdir data
# vim .env
INSTANCE_URL=http://your-gitea.example.com
REGISTRATION_TOKEN=your_token_here
RUNNER_NAME=my-runner-01
RUNNER_LABELS=linux,self-hosted
# vim docker-compose.yml
version: "3.8"
services:
runner:
image: gitea/act_runner:0.2.13
environment:
CONFIG_FILE: /config.yaml
GITEA_INSTANCE_URL: "${INSTANCE_URL}"
GITEA_RUNNER_REGISTRATION_TOKEN: "${REGISTRATION_TOKEN}"
GITEA_RUNNER_NAME: "${RUNNER_NAME}"
GITEA_RUNNER_LABELS: "${RUNNER_LABELS}"
volumes:
- ./config.yaml:/config.yaml
- ./data:/data
- /var/run/docker.sock:/var/run/docker.sock
$ ls
config.yaml data docker-compose.yml

启动容器

1
$ docker-compose up -d

关闭forcePull

Gitea提供了用于Job运行阶段的构建镜像:gitea/runner-images,常用的有

1
2
$ docker image ls | grep ubuntu
docker.gitea.com/runner-images ubuntu-latest fb5e48a0afc7 2 weeks ago 1.56GB

可以先下载到本地,然后在act_runner config.yaml关闭强制更新选项

1
2
# Pull docker image(s) even if already present
force_pull: true

修改为false,重新启动act_runner,这样后续actions运行时不会主动拉取线上镜像文件

1
2
3
4
5
6
7
8
9
10
11
12
13
$ docker-compose down
WARN[0000] /home/zjykzj/software/act_runner/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
[+] Running 2/2
✔ Container act_runner-runner-1 Removed 0.0s
Network act_runner_default Removed
$ docker-compose up -d
WARN[0000] /home/zjykzj/software/act_runner/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
[+] Running 2/2
Network act_runner_default Created 0.0s
✔ Container act_runner-runner-1 Started
$ docker logs -f 4f7
time="2025-11-17T13:40:44Z" level=info msg="Starting runner daemon"
time="2025-11-17T13:40:44Z" level=info msg="runner: my-runner-01, with version: v0.2.13, with labels: [ubuntu-latest ubuntu-22.04 ubuntu-20.04], declare successfully"

简单Workflow/Job

在Gitea上新建仓库ActionDemo,实现每次推送都能够触发workflow

demo.yaml

下载工程到本地后创建配置文件.gitea/workflows/demo.yaml

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
# 整个工作流的名称,在 Gitea UI 中显示为 "Gitea Actions Demo"
name: Gitea Actions Demo

# 每次运行(run)时动态显示的标题,包含触发用户和表情符号
# gitea.actor 表示触发该工作流的用户名(如 git push 的提交者)
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀

# 定义触发条件:仅在 push 事件发生时运行
on:
push:
# 匹配所有分支(包括嵌套分支,如 feature/login、release/v1.0 等)
branches:
- '**'
# 明确忽略所有 tag 的推送(即使推送了 tag,也不会触发此 workflow)
tags-ignore:
- '*'

# 定义工作流中的任务(jobs)
jobs:
# 任务名称:Explore-Gitea-Actions
Explore-Gitea-Actions:
# 指定运行环境:使用最新版 Ubuntu 系统的 runner
runs-on: ubuntu-latest

# 任务包含的具体步骤(按顺序执行)
steps:
# 步骤1:打印触发事件类型(例如 push)
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."

# 步骤2:打印运行器的操作系统(如 Linux)
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"

# 步骤3:打印当前分支引用(如 refs/heads/main)和仓库名(如 user/repo)
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."

- name: Clone repository manually
run: |
# 从 gitea.ref 提取纯分支名(去掉 refs/heads/)
FULL_REF="${{ gitea.ref }}"
BRANCH="${FULL_REF#refs/heads/}" # bash 参数扩展:移除前缀

# 克隆指定分支
# git clone --branch="$BRANCH" --depth=1 https://your-gitea-instance.com/${{ gitea.repository }} .
git clone --branch="$BRANCH" --depth=1 http://172.23.217.55:3000/${{ gitea.repository }} .

# 步骤5:提示仓库代码已成功克隆
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."

# 步骤6:提示工作流环境已准备就绪,可开始测试
- run: echo "🖥️ The workflow is now ready to test your code on the runner."

# 步骤7:列出工作区目录下的所有文件,验证代码是否检出成功
# gitea.workspace 是 runner 上存放代码的根路径
- name: List files in the repository
run: |
ls -al ${{ gitea.workspace }}

# 步骤8:打印当前工作目录路径(用于调试)
- name: Pwd
run: |
pwd

# 步骤9:打印当前任务的状态(通常是 success,除非前面步骤失败)
- run: echo "🍏 This job's status is ${{ job.status }}."

将更新提交上传到Gitea,就能够触发Actions功能

注意:每个yaml文件表示一个workflow,一个仓库可以创建多个yaml文件,一个workflow yaml文件可以配置多个Job。

workflow语法

更多变量以及workflow语法可以查看:Workflow syntax for GitHub Actions

预定义action

Gitea可以复用很多Github预定义的actions:Quickstart for GitHub Actions。比如

1
2
3
4
# 步骤4:使用官方 checkout action 将仓库代码克隆到运行器
# actions/checkout@v4 是兼容 Gitea Actions 的标准动作(需 runner 能访问)
- name: Check out repository code
uses: actions/checkout@v4

不过使用的时候发现这个action需要访问到Github,建议使用git clone替代。

推送文件到其他仓库

创建新的workflow,将本仓库public文件夹下面的文件推送到指定仓库。完整执行流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tag v* 

触发 workflow

克隆源仓库(ActionDemo)

检出对应 commit

检查 public/ 是否存在

配置 Git 用户

加载 SSH 私钥(来自 secrets)

克隆目标仓库(ActionDemo-Pages)via SSH

清空目标仓库内容(保留 .git)

复制 public/ 内容到目标仓库

提交 + 推送

Pages 自动更新

deploy.yaml

新建.gitea/workflows/deploy.yaml文件

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
# 整个工作流的名称,在 Gitea UI 中显示为 "Deploy Public to Pages Repo"
name: Deploy Public to Pages Repo

# 触发条件:仅当推送的 tag 名称匹配 'v*' 模式时运行(例如 v1.0、v2.3.4)
# 这通常用于版本发布场景,避免每次提交都触发部署
on:
push:
tags:
- 'v*'

# 定义工作流中的任务(jobs)
jobs:
# 任务名称:deploy-public,负责将构建产物部署到 Pages 仓库
deploy-public:
# 指定运行环境:使用最新版 Ubuntu 的 runner
runs-on: ubuntu-latest

# 任务包含的具体步骤(按顺序执行)
steps:

# 步骤1:手动克隆当前源仓库(替代 actions/checkout)
# 使用 HTTP 地址直接 clone,适用于公开仓库或内网可匿名访问的仓库
# 克隆后立即检出触发本次 workflow 的具体 commit(由 gitea.sha 提供)
- name: Clone current repository
run: |
git clone http://172.23.217.55:3000/zjykzj/ActionDemo.git .
git checkout ${{ gitea.sha }}

# 步骤2:验证是否存在 public/ 目录
# 该目录通常由静态站点生成器(如 Hugo、VitePress)生成
# 如果不存在,说明构建未完成或路径错误,立即终止任务
- name: Verify public directory exists
run: |
if [ ! -d "public" ]; then
echo "❌ public/ directory not found!"
exit 1
fi

# 步骤3:配置 Git 全局用户信息
# 后续的 git commit 需要有效的 user.name 和 user.email
# 这里使用虚拟身份 "Gitea Actions Bot",符合自动化场景惯例
- name: Configure Git identity
run: |
git config --global user.name "Gitea Actions Bot"
git config --global user.email "actions@gitea.local"

# 步骤4:设置 SSH 认证密钥,用于写入目标 Pages 仓库
# 从 Gitea Secrets 中读取名为 DEPLOY_KEY 的私钥
# 将其写入 ~/.ssh/id_ed25519 并设置安全权限(600)
# 同时通过 ssh-keyscan 获取 Gitea SSH 主机公钥,避免首次连接交互确认
# 注意:Gitea SSH 服务运行在非标准端口 2222,因此需指定 -p 2222
- name: Setup SSH for Gitea
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
mkdir -p ~/.ssh
echo "$DEPLOY_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -p 2222 172.23.217.55 >> ~/.ssh/known_hosts

# 步骤5:通过 SSH 克隆目标 Pages 仓库
# 使用 ssh:// 协议显式指定端口 2222
# 克隆到本地子目录 target-repo/,便于后续操作而不影响当前工作区
- name: Clone target repository via SSH
run: |
git clone ssh://git@172.23.217.55:2222/zjykzj/ActionDemo-Pages.git target-repo

# 步骤6:将 public/ 内容同步到目标仓库
# 进入 target-repo 目录后:
# - 确保处于 main 分支(若不存在则创建)
# - 删除除 .git 外的所有文件和目录(保留 Git 历史)
# - 将 ../public/ 下所有内容复制到当前目录(即 target-repo/)
# 实现“完全替换”目标仓库内容为最新构建产物
- name: Sync public content to target repo
run: |
cd target-repo
git checkout main || git checkout -b main
find . -maxdepth 1 ! -name '.git' ! -name '.' -exec rm -rf {} + 2>/dev/null || true
cp -r ../public/* ./

# 步骤7:提交变更并推送到远程目标仓库
# 添加所有新文件,提交信息包含源仓库名和触发 commit 的 SHA
# 最后将 main 分支推送到 origin,完成部署
# 成功推送后,Gitea Pages(若启用)会自动更新网站内容
- name: Commit and push to target repository
run: |
cd target-repo
git add .
git commit -m "Deploy from ${{ gitea.repository }}@${{ gitea.sha }}"
git push origin main

密钥配置

生成密钥对(不要设置 passphrase,否则自动化会卡住

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 生成无密码的 Ed25519 密钥对
$ ssh-keygen -t ed25519 -f deploy_key -N "" -C "gitea-deploy-key"
Generating public/private ed25519 key pair.
Your identification has been saved in deploy_key
Your public key has been saved in deploy_key.pub
The key fingerprint is:
SHA256:1zHk2jGLV+cnQ9tWQXdb+fu7Jjo6Jgdn9B+KQ7sIHAk gitea-deploy-key
The key's randomart image is:
+--[ED25519 256]--+
| . .o=|
| o .*|
| E * o.+|
| . . . = O =o|
| o S = = + *|
| . .. = o . =.|
| o = o o . .|
| ...B o o ..|
| .+o=.o ooo|
+----[SHA256]-----+
$ ls
deploy_key deploy_key.pub

在Gitea新建仓库ActionDemo-Pages

deploy_key.pub添加到ActionDemo-Pages仓库的Deploy Key(勾选写权限)

deploy_key内容粘贴到ActionDemo仓库的Secrets → DEPLOY_KEY

注意:Secrets的名称要跟deploy.yaml保持一致,当前命名为DEPLOY_KEY

文件推送

保存修改打tag v0.1.0,上传到Gitea,就能够触发Deploy workflow。此时没有public文件夹,所以报错

新建public文件夹,新建index.html文件

1
<h1>Hello Pages</h1>

重新打tag v0.1.1,上传到Gitea,此时能够发现文件index.html能够推送到仓库``

如果本次提交的内容不涉及到public文件夹,那么在action中最后一步也会提示报错

推送文件到远程服务器

创建新的workflow,将本仓库public文件夹下面的文件推送到远程服务器,并且使用nginx托管web服务。完整执行流程

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
打 tag v* 

触发 workflow

克隆源仓库(ActionDemo)

检出对应 commit

检查 public/ 是否存在

配置 SSH 密钥(用于连接远程服务器,私钥来自 secrets)

生成时间戳作为版本标识

打包 public/ 目录为 tar.gz

通过 scp 上传压缩包到远程服务器(如 /tmp/)

通过 ssh 在远程服务器执行部署脚本:
- 创建新版本目录(/data/workspace/releases/<timestamp>
- 解压文件到新版本目录
- 设置文件权限(如 chmod 755)
- 原子切换软链接(/data/workspace/blogs → 新版本)
- 清理旧版本(保留最近 N 个)
- 重启 Nginx 容器(使 volume 重新挂载新目录)

浏览器通过服务器 IP 即可访问最新内容

upload.yaml

新建.gitea/workflows/upload.yaml文件

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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 工作流名称:将静态站点上传并部署到香港服务器(使用 Docker 运行的 Nginx)
name: Upload & Deploy to Hong Kong Server (Docker Nginx)

# 触发条件:当推送带有 'v' 前缀的 Git 标签时触发(例如 v1.0.0、v2.3.1)
on:
push:
tags:
- 'v*'

# 定义一个名为 upload-and-deploy 的作业
jobs:
upload-and-deploy:
# 指定运行环境为 ubuntu-latest(Gitea Actions 使用兼容镜像)
runs-on: ubuntu-latest

# 该作业包含多个步骤(steps)
steps:
# === 步骤 1:克隆当前 Gitea 仓库代码(替代 GitHub 的 actions/checkout)===
- name: Clone current repository
run: |
# 使用 HTTP 协议从内网 Gitea 地址克隆仓库(因未启用 HTTPS)
git clone http://172.23.217.55:3000/zjykzj/ActionDemo.git .
# 切换到当前触发事件对应的 commit(由 Gitea 提供的内置变量 gitea.sha)
git checkout ${{ gitea.sha }}

# === 步骤 2:验证 public 目录是否存在(确保静态文件已生成)===
- name: Verify public directory exists
run: |
# 如果 public/ 目录不存在,报错并退出
if [ ! -d "public" ]; then
echo "❌ public/ not found!"
exit 1
fi

# === 步骤 3:配置 SSH 密钥,用于连接香港服务器 ===
- name: Setup SSH key for HK server
env:
# 香港服务器 IP 地址
HK_HOST: 47.240.173.235
# 从 Gitea Secrets 中读取私钥(需提前在仓库 Settings → Secrets 中配置)
HK_SERVER_KEY: ${{ secrets.HK_SERVER_KEY }}
run: |
# 创建 .ssh 目录(如果不存在)
mkdir -p ~/.ssh
# 将私钥内容写入文件
echo "$HK_SERVER_KEY" > ~/.ssh/id_ed25519_hk
# 设置私钥权限为 600(仅所有者可读写)
chmod 600 ~/.ssh/id_ed25519_hk
# 获取服务器 SSH 公钥指纹,避免首次连接时交互确认
ssh-keyscan -p 22 ${HK_HOST} >> ~/.ssh/known_hosts

# === 步骤 4:生成时间戳,用于版本标识(格式:YYYYMMDDHHMMSS)===
- name: Generate timestamp
id: timestamp # 设置 step ID,以便后续引用输出
run: |
# 将时间戳写入 GITHUB_OUTPUT,供后续步骤使用
echo "TS=$(date -u +%Y%m%d%H%M%S)" >> "$GITHUB_OUTPUT"

# === 步骤 5:打包 public/ 目录为 tar.gz 压缩包 ===
- name: Package public directory
run: |
# 以时间戳命名压缩包,并从 public 目录内部打包(避免顶层目录)
tar -czf site-${{ steps.timestamp.outputs.TS }}.tar.gz -C public .

# === 步骤 6:通过 SCP 将压缩包上传到香港服务器的 /tmp 目录 ===
- name: Upload package to HK server
env:
HK_HOST: 47.240.173.235
run: |
# 读取时间戳变量
TS=${{ steps.timestamp.outputs.TS }}
# 使用 scp 命令上传,指定私钥和端口
scp -i ~/.ssh/id_ed25519_hk -P 22 \
site-${TS}.tar.gz \
root@${HK_HOST}:/tmp/site-${TS}.tar.gz

# === 步骤 7:在远程服务器上执行部署脚本 ===
- name: Run deployment on HK server
env:
HK_HOST: 47.240.173.235
run: |
# 读取时间戳
TS=${{ steps.timestamp.outputs.TS }}
# 定义部署根目录
BASE_DIR="/data/workspace"
# 存放所有历史版本的目录
RELEASES_DIR="${BASE_DIR}/releases"
# 新版本目录路径(含时间戳)
NEW_RELEASE="${RELEASES_DIR}/${TS}"
# 当前生效的软链接路径(必须与 docker-compose.yml 中的 volume 路径一致)
CURRENT_LINK="${BASE_DIR}/blogs"

# 通过 SSH 执行远程命令(以 root 身份)
ssh -i ~/.ssh/id_ed25519_hk -p 22 root@${HK_HOST} "
# 启用严格错误处理:任一命令失败则整个脚本退出
set -e

# 创建 releases 目录(若不存在)
mkdir -p ${RELEASES_DIR}

# 创建新版本目录
mkdir -p ${NEW_RELEASE}

# 解压上传的压缩包到新版本目录
tar -xzf /tmp/site-${TS}.tar.gz -C ${NEW_RELEASE}

# 设置目录权限为 755,确保 Nginx 容器(通常以 nginx 用户运行)可读
chmod -R 755 ${NEW_RELEASE}

# 原子切换软链接:
# 1. 先创建临时软链接指向新版本
ln -sfn ${NEW_RELEASE} ${CURRENT_LINK}.new
# 2. 用 mv -T 原子替换原软链接(避免中间状态)
mv -T ${CURRENT_LINK}.new ${CURRENT_LINK}

# 删除临时压缩包
rm -f /tmp/site-${TS}.tar.gz

# 自动清理旧版本:进入 releases 目录,按时间倒序列出,删除第6个及之后的(保留最近5个)
cd ${RELEASES_DIR} && \
ls -1t | tail -n +6 | xargs -r rm -rf

# 重启 Nginx 容器(关键!因为 Docker volume 在启动时解析软链接,
# 后续变更对容器不可见,必须重启才能重新挂载新目录)
docker restart nginx

# 输出成功信息
echo '✅ Deployment complete. Nginx serving new version via volume.'
"

# === 步骤 8:本地输出部署成功信息(用于 Gitea UI 显示)===
- name: Report success
run: |
# 打印部署完成消息,包含版本时间戳
echo "✅ Deployed version ${{ steps.timestamp.outputs.TS }} to Hong Kong server!"

密钥配置

生成密钥对(不要设置 passphrase,否则自动化会卡住

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 生成密钥对(不要设置 passphrase,否则自动化会卡住)
$ ssh-keygen -t ed25519 -f hk-deploy-key -N "" -C "gitea-deploy-key"
Generating public/private ed25519 key pair.
Your identification has been saved in hk-deploy-key
Your public key has been saved in hk-deploy-key.pub
The key fingerprint is:
SHA256:YJ4CKOWTy+dPYq5zfTzV3VzN1AthRBGYFPwoZdEu3QA gitea-deploy-key
The key's randomart image is:
+--[ED25519 256]--+
| . oEXB+ .|
| + . *.+ o|
|o = o o = +oo|
|.. + o o . o + o+|
| o o o S .... o.|
| o . . . . o|
| +... . |
| .o.+. + |
| .+. .. . |
+----[SHA256]-----+

# 生成后你会得到两个文件:
# - 私钥:hk-deploy-key ← 交给 Gitea Secrets
# - 公钥:hk-deploy-key.pub ← 上传到远程服务器
hk-deploy-key hk-deploy-key.pub

将公钥内容配置到远程服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 远程服务器
# 确保 .ssh 目录存在且权限正确
mkdir -p ~/.ssh
chmod 700 ~/.ssh

# 将公钥内容追加到 authorized_keys
cat hk-deploy-key.pub | ssh root@47.240.173.235 "cat >> ~/.ssh/authorized_keys"

# 或手动复制公钥内容并粘贴:
nano ~/.ssh/authorized_keys

# 设置权限(非常重要!SSH 对权限敏感)
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh

将私钥内容粘贴到ActionDemo仓库的Secrets → HK_SERVER_KEY

文件上传

tag v*,上传更新到Gitea,触发Gitea Actions操作

服务器最终目录结构如下:

1
2
3
4
5
6
/data/workspace/
├── releases/
│ ├── 20251118190000/
│ ├── 20251118191500/
│ └── 20251118193022/ ← 最新
└── blogs → /data/workspace/releases/20251118193022

web服务

使用nginx托管web服务,创建docker-compose.yml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version:  "3"
services:
nginx:
container_name: nginx
image: nginx
ports:
- "80:80"
- "443:443"
volumes:
- "/data/workspace/blogs:/opt/www"
- "~/nginx/ssl:/etc/nginx/conf"
- "~/nginx/logs:/var/log/nginx"
- "~/nginx/conf.d:/etc/nginx/conf.d"
- "~/nginx/nginx.conf:/etc/nginx/nginx.conf"
restart: always

创建配置文件,确保浏览器访问

1
2
3
4
5
6
7
8
9
10
11
12
13
# 在香港服务器执行
$ mkdir -p ~/nginx/conf.d
$ vim ~/nginx/conf.d/default.conf
server {
listen 80;
server_name _; # 匹配任意 host

location / {
root /opt/www; # ← 指向你挂载的目录
index index.html;
try_files $uri $uri/ =404;
}
}

启动nginx容器

1
docker-compose up -d

在浏览器输入网址,Perfect !!!