服务器操作指北(9)Gitea 部署与 FreeIPA 认证配置
创建于 2026-09-19
更新于 2026-09-19
科技
k3s
freeipa
ldap
gitea
postgresql
ssh
15820 字 · 约 53 分钟

前言

由于实验室需要集中管理项目代码、实验脚本及环境配置,故而在 K3s 中部署 Gitea,并接入 FreeIPA 统一用户认证。仓库通过组织和团队分配权限,使用 Issue 和 Pull Request 进行项目协作,共享文档另由 Nextcloud 管理。

之前在服务器操作指北(4)GitLab 私有化部署中记录过 GitLab 的安装,本篇记录 Gitea 的部署方式。

服务器操作指北(8)FreeIPA、K3s 部署与 HTTPS 证书配置已经配置了 FreeIPA、K3s 和 Traefik,本篇继续记录 Gitea 的部署、LDAP 认证及 HTTPS、SSH 访问设置。下面从空数据目录开始,通过独立的 Kubernetes 清单安装 PostgreSQL 和 Gitea,再配置 FreeIPA 认证源。

本文使用版本为 Gitea 1.27.3PostgreSQL 15.19。文中的域名、节点名称、目录和外部端口均为示例,使用时自行修改。

  • 20260919:补充初始化访问、安装锁定、LDAP 工具与查询账户、测试仓库及持久化检查步骤。

本篇依赖第8篇完成的 K3s、内部 DNS、FreeIPA 客户端入域及 Traefik 正式证书。默认在已入域的控制节点 host-a 执行 sudo k3s kubectl,无需在工作电脑另装 kubectl。浏览器和 Git 客户端所在电脑也要能解析内网区域;下文另行标注客户端操作。

开始前在控制节点检查:

bash
1
2
3
4
5
6
7
8
sudo apt update sudo apt install -y ldap-utils openssl git sudo k3s kubectl get nodes sudo k3s kubectl -n kube-system get svc traefik getent hosts ipa.lab.example.com getent hosts git.lab.example.com test -r /etc/ipa/ca.crt curl -I https://git.lab.example.com:8443/

此时还没有业务路由,最后一项允许返回 404,但不能有证书错误或连接超时。三个节点应为 Ready;域名应指向第8篇指定的入口。

一、部署准备

1.1 确认服务与访问方式

Gitea 使用 PostgreSQL 保存用户、仓库元数据和认证源配置,仓库文件、附件及应用配置保存在 /data。两部分都需要持久化,不能只备份数据库。

本篇沿用上一文的 lab.example.com 示例区域,配置如下:

项目 示例配置
Gitea 域名 git.lab.example.com
FreeIPA 域名 ipa.lab.example.com
HTTPS 地址 https://git.lab.example.com:8443/
Git SSH 对外端口 22222/TCP
Gitea 容器网页端口 3000/TCP
Gitea 容器 SSH 端口 22/TCP
PostgreSQL 集群内 5432/TCP
数据节点 host-a

此处使用带 OpenSSH 的普通 Gitea 镜像,不使用 rootless 标签,也不启动 Gitea 内置 SSH 服务。不同镜像的目录、运行用户和 SSH 监听端口不能混用,镜像部署方式参考 Gitea Docker 文档

FreeIPA 的 LDAPS 使用 636/TCP,容器需要能够解析并访问 IPA 内网地址。网页前面的公共 HTTPS 证书与 LDAP 后端的 IPA CA 分别配置。

1.2 创建命名空间与数据目录

bash
1
2
3
4
5
6
7
8
9
10
11
12
sudo k3s kubectl create namespace gitea # 在数据所在节点执行,自行修改目录 sudo install -d -m 0750 /srv/example/gitea sudo install -d -m 0750 /srv/example/gitea-db # 普通 Gitea 镜像的 git 用户使用本文指定的 UID/GID sudo chown 1000:1000 /srv/example/gitea # 确认目录实际落在数据盘,而不是未挂载时的根目录 findmnt -T /srv/example/gitea findmnt -T /srv/example/gitea-db

本例将应用与数据库固定到同一数据节点,采用单副本。其他节点不会自动拥有这些目录中的数据;本地持久卷适合目前的部署方式,但不提供跨节点数据复制。

1.3 创建 PV 与 PVC

保存为 gitea-storage.yaml,其中 host-a 替换为 kubectl get nodes 中的数据节点名称:

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
apiVersion: v1 kind: PersistentVolume metadata: name: example-gitea-data spec: capacity: storage: 20Gi accessModes: [ReadWriteOnce] persistentVolumeReclaimPolicy: Retain storageClassName: "" local: path: /srv/example/gitea nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: [host-a] --- apiVersion: v1 kind: PersistentVolume metadata: name: example-gitea-db spec: capacity: storage: 10Gi accessModes: [ReadWriteOnce] persistentVolumeReclaimPolicy: Retain storageClassName: "" local: path: /srv/example/gitea-db nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: [host-a] --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: gitea-data namespace: gitea spec: accessModes: [ReadWriteOnce] storageClassName: "" volumeName: example-gitea-data resources: requests: storage: 20Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: gitea-db namespace: gitea spec: accessModes: [ReadWriteOnce] storageClassName: "" volumeName: example-gitea-db resources: requests: storage: 10Gi
bash
1
2
sudo k3s kubectl apply -f gitea-storage.yaml sudo k3s kubectl -n gitea get pvc

两个 PVC 应为 Bound。Retain 防止删除 PVC 后直接回收数据,但不会自动制作备份;容量声明也不是宿主目录的磁盘配额。

二、部署 PostgreSQL 与 Gitea

2.1 创建数据库密码

应用和数据库引用同一个 Secret,避免分别填写密码造成不一致。首次部署可生成随机密码并保存在 root 受限文件中:

bash
1
2
3
4
5
sudo install -d -m 0700 /root/example-gitea sudo sh -c 'umask 077; openssl rand -hex 32 | tr -d "\n" > /root/example-gitea/db-password' sudo k3s kubectl -n gitea create secret generic gitea-db-auth \ --from-file=password=/root/example-gitea/db-password

PostgreSQL 镜像中的初始化环境变量只在空数据目录时创建数据库和用户。安装完成后如需更换密码,需要同时修改数据库用户密码和 Secret,不能只重新生成凭据文件。

2.2 部署数据库

保存为 gitea-postgres.yaml

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
apiVersion: apps/v1 kind: Deployment metadata: name: gitea-db namespace: gitea spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: gitea-db template: metadata: labels: app: gitea-db spec: nodeSelector: kubernetes.io/hostname: host-a containers: - name: postgres image: postgres:15.19 env: - name: POSTGRES_DB value: gitea - name: POSTGRES_USER value: gitea - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: gitea-db-auth key: password - name: PGDATA value: /var/lib/postgresql/data/pgdata ports: - name: postgres containerPort: 5432 readinessProbe: exec: command: [pg_isready, -U, gitea, -d, gitea] initialDelaySeconds: 10 periodSeconds: 10 volumeMounts: - name: database mountPath: /var/lib/postgresql/data volumes: - name: database persistentVolumeClaim: claimName: gitea-db --- apiVersion: v1 kind: Service metadata: name: gitea-db namespace: gitea spec: type: ClusterIP selector: app: gitea-db ports: - name: postgres port: 5432 targetPort: postgres
bash
1
2
sudo k3s kubectl apply -f gitea-postgres.yaml sudo k3s kubectl -n gitea rollout status deployment/gitea-db

数据库 Service 只在集群内部使用,不配置公网端口转发。示例使用单实例 Deployment 和 Recreate,升级会中断服务,应安排维护窗口。若数据节点带有 NoSchedule 污点,数据库和后面的 Gitea Pod 都需补充对应 tolerations。

2.3 导入 IPA CA

从已正确入域的客户端取得 /etc/ipa/ca.crt,核对它与 IPA 服务端的 CA 指纹一致。这里导入的是公共证书,不是 CA 私钥。

bash
1
2
3
4
openssl x509 -in /etc/ipa/ca.crt -noout -subject -fingerprint -sha256 sudo k3s kubectl -n gitea create configmap ipa-ca \ --from-file=ipa-ca.crt=/etc/ipa/ca.crt

后面的 initContainer 会把镜像原有公共 CA 与 IPA CA 合并,再挂载到 Gitea 中。这样既能校验 FreeIPA 的 LDAPS,也保留访问公共 HTTPS 服务所需的 CA。

不能只把宿主机加入 IPA 就认为容器也信任 IPA CA,容器有自己的文件系统与证书库。也不要用勾选 Skip TLS Verify 来代替证书安装。

2.4 部署 Gitea

保存为 gitea.yaml。环境变量采用 Gitea 的 GITEA__配置节__配置项 格式,镜像启动时会据此生成或更新配置。

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
apiVersion: apps/v1 kind: Deployment metadata: name: gitea namespace: gitea spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: gitea template: metadata: labels: app: gitea spec: nodeSelector: kubernetes.io/hostname: host-a initContainers: - name: prepare-ca image: docker.io/gitea/gitea:1.27.3 command: [/bin/sh, -ec] args: - | cat /etc/ssl/certs/ca-certificates.crt /ipa/ipa-ca.crt > /trust/ca-certificates.crt chmod 0644 /trust/ca-certificates.crt volumeMounts: - name: ipa-ca mountPath: /ipa readOnly: true - name: trust mountPath: /trust containers: - name: gitea image: docker.io/gitea/gitea:1.27.3 env: - name: USER_UID value: "1000" - name: USER_GID value: "1000" - name: GITEA__database__DB_TYPE value: postgres - name: GITEA__database__HOST value: gitea-db:5432 - name: GITEA__database__NAME value: gitea - name: GITEA__database__USER value: gitea - name: GITEA__database__PASSWD valueFrom: secretKeyRef: name: gitea-db-auth key: password - name: GITEA__database__SSL_MODE value: disable - name: GITEA__server__PROTOCOL value: http - name: GITEA__server__HTTP_PORT value: "3000" - name: GITEA__server__DOMAIN value: git.lab.example.com - name: GITEA__server__ROOT_URL value: https://git.lab.example.com:8443/ - name: GITEA__server__SSH_DOMAIN value: git.lab.example.com - name: GITEA__server__SSH_PORT value: "22222" - name: GITEA__server__START_SSH_SERVER value: "false" - name: GITEA__service__DISABLE_REGISTRATION value: "true" - name: SSL_CERT_FILE value: /etc/ssl/certs/ca-certificates.crt ports: - name: http containerPort: 3000 - name: ssh containerPort: 22 readinessProbe: httpGet: path: /api/healthz port: http initialDelaySeconds: 20 periodSeconds: 10 volumeMounts: - name: data mountPath: /data - name: trust mountPath: /etc/ssl/certs/ca-certificates.crt subPath: ca-certificates.crt readOnly: true volumes: - name: data persistentVolumeClaim: claimName: gitea-data - name: ipa-ca configMap: name: ipa-ca - name: trust emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: gitea-http namespace: gitea spec: selector: app: gitea ports: - name: http port: 3000 targetPort: http

这里的 emptyDir 只保存每次启动重新生成的 CA 合集,业务数据仍在 PVC。IPA CA 发生更新后,需要重建 Pod 重新合并证书。

示例数据库连接采用集群内部明文传输;ClusterIP 不等于流量加密,其他不受信任工作负载能否访问还取决于网络策略。如需跨不受信任网络连接数据库,应另行配置 PostgreSQL TLS。

bash
1
2
3
sudo k3s kubectl apply -f gitea.yaml sudo k3s kubectl -n gitea get pods sudo k3s kubectl -n gitea logs deployment/gitea --tail=100

2.5 首次初始化

先通过只监听回环地址的临时端口完成初始化。在控制节点执行,保持这个终端运行:

bash
1
2
3
sudo k3s kubectl -n gitea get pods -l app=gitea # Pod 应已进入 Running;使用 Pod 转发,不依赖安装前的 readiness 状态 sudo k3s kubectl -n gitea port-forward deployment/gitea 3000:3000 --address=127.0.0.1

若已经远程桌面登录控制节点,用服务器浏览器访问 http://127.0.0.1:3000/。使用自己电脑的浏览器时,另开本地终端建立 SSH 隧道,SSH 用户自行替换:

bash
1
ssh -N -L 3000:127.0.0.1:3000 your-admin@192.168.50.10

再在自己电脑打开同一地址。安装页面中数据库类型为 PostgreSQL,地址 gitea-db:5432,数据库与用户均为 gitea。数据库密码通常已由环境变量预填;若需要手工输入,在可信控制节点用 sudo cat /root/example-gitea/db-password 查看,仅在安装页面使用,不复制到日志或文章。

站点 URL 填 https://git.lab.example.com:8443/,展开管理员账户设置,创建独立本地管理员 site-admin。提交安装后可能跳到尚未配置入口的正式 URL;先检查应用日志与配置确认安装完成,不要反复初始化数据库。

在另一条控制节点终端检查安装锁,再写入最终清单:

bash
1
2
sudo k3s kubectl -n gitea exec deployment/gitea -- \ sh -c 'grep -i "^INSTALL_LOCK" /data/gitea/conf/app.ini'

输出应为 INSTALL_LOCK = true。在 gitea.yamlcontainers[name=gitea].env 列表增加:

yaml
1
2
- name: GITEA__security__INSTALL_LOCK value: "true"
bash
1
2
sudo k3s kubectl apply -f gitea.yaml sudo k3s kubectl -n gitea rollout status deployment/gitea --timeout=300s

只在安装已经成功后添加这个变量。 空目录尚未初始化时提前锁定,会跳过安装页面。完成后在端口转发和 SSH 隧道终端按 Ctrl-C 退出,再配置下一节入口并用本地管理员登录。

本地管理员保留作认证源维护用途,不需要与 IPA 管理员同名。

三、配置 HTTPS 和 SSH 入口

3.1 HTTPS 反向代理

沿用上一篇已经配置的 Traefik business 入口与默认泛域名证书,创建 gitea-ingress.yaml

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: traefik.io/v1alpha1 kind: IngressRoute metadata: name: gitea-https namespace: gitea spec: entryPoints: [business] routes: - match: Host(`git.lab.example.com`) kind: Rule services: - name: gitea-http port: 3000 tls: {}
bash
1
2
sudo k3s kubectl apply -f gitea-ingress.yaml curl -IL https://git.lab.example.com:8443/

Traefik 终止 HTTPS 后,通过集群内 HTTP 访问 Gitea,所以 Gitea 的 PROTOCOL=httpROOT_URL=https://... 并不冲突。前者是应用监听协议,后者用于生成外部链接,具体参数可参考 Gitea 配置说明

内网 DNS 将业务域名解析到内部入口,公网 DNS 指向公开入口,域名、协议和端口保持一致。若页面能打开但登录跳回旧地址,优先检查 ROOT_URL 与 Deployment 环境变量,不只修改容器里的 app.ini。

3.2 SSH 使用独立端口

HTTPS 与 Git SSH 是两种协议。本文网页使用 8443,SSH 使用 22222,不能把 SSH 克隆地址也填成 HTTPS 端口。

创建 gitea-ssh.yaml

yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1 kind: Service metadata: name: gitea-ssh namespace: gitea spec: type: LoadBalancer ipFamilyPolicy: PreferDualStack externalTrafficPolicy: Local selector: app: gitea ports: - name: ssh port: 22222 targetPort: ssh protocol: TCP
bash
1
2
sudo k3s kubectl apply -f gitea-ssh.yaml sudo k3s kubectl -n gitea get svc gitea-ssh -o wide

K3s 使用 ServiceLB 时,应确认数据节点上有可运行的 ServiceLB Pod,且没有端口冲突或污点阻止调度。externalTrafficPolicy: Local 要求访问有本地 Gitea 后端的节点;路由器转发目标应选实际承载 Gitea 的节点,不能任意选择一个工作节点。

端口关系为:

text
1
2
3
4
客户端 TCP 22222 → 路由器 TCP 22222 端口转发 → 数据节点的 Gitea SSH Service 22222 → Gitea 容器 OpenSSH 22

SSH_PORT=22222 用于生成给用户看的克隆地址,不会把容器 OpenSSH 的监听端口改成 22222。SSH_LISTEN_PORT 属于 Gitea 内置 SSH 服务的配置,本例没有启用该服务,不需要设置。

路由器需要单独建立 SSH 转发规则。内网能握手、网页能访问,都不能证明公网 SSH 转发已经存在。实际环境中已检查公网映射并收到 SSH 协议响应,确认此路径可达。

四、接入 FreeIPA

4.1 配置应用查询账户与用户组

这里采用 LDAP via BindDN。Gitea 先使用查询账户查找用户 DN,再使用用户提交的密码认证。查询账户无需加入 IPA 管理员组,也不要直接把 Directory Manager 密码保存到 Gitea。

先在已入域控制节点执行 sudo apt install -y ldap-utils,确认 /etc/ipa/ca.crt 存在。FreeIPA 可以为应用创建位于 cn=sysaccounts,cn=etc 下的系统绑定账户,参考 FreeIPA LDAP 说明。以下是 LDIF 模板,保存为受限文件 gitea-bind.ldif,替换 DN 与密码;不要提交到配置仓库:

ldif
1
2
3
4
5
6
7
8
dn: uid=gitea-bind,cn=sysaccounts,cn=etc,dc=lab,dc=example,dc=com changetype: add objectClass: account objectClass: simpleSecurityObject uid: gitea-bind userPassword: REPLACE_WITH_A_UNIQUE_PASSWORD passwordExpirationTime: 20380119031407Z nsIdleTimeout: 0

先执行 umask 077 再用编辑器创建 LDIF,避免密码文件一度对其他用户可读。示例密码必须换成独立随机值,可在密码管理器中生成并保存。

有效期是需要维护的配置,应按自己的凭据轮换计划设置,不能把模板日期当成永不过期。文件只允许管理员读取,通过可信客户端的 LDAPS 导入:

bash
1
2
3
4
5
6
chmod 0600 gitea-bind.ldif # -W 交互输入 Directory Manager 密码;不是普通 IPA admin 密码 LDAPTLS_CACERT=/etc/ipa/ca.crt ldapmodify \ -H ldaps://ipa.lab.example.com:636 \ -x -D 'cn=Directory Manager' -W -f gitea-bind.ldif

导入后妥善保存应用凭据,移除不再需要的明文 LDIF。Directory Manager 仅用于这一步管理操作;后续 Gitea 绑定使用 gitea-bind。该账户应只拥有所需查询权限,若环境定制过 LDAP ACI,需实际验证它能读取所用的用户和组属性。

再建立允许使用 Gitea 的用户组。yourname 使用第8篇已创建并完成首次改密的 IPA 用户;先执行 kinit adminipa user-show yourname --all 确认存在。以下在已入域控制节点执行:

bash
1
2
3
kinit admin ipa group-add gitea-users --desc='Users allowed to access Gitea' ipa group-add-member gitea-users --users=yourname

用户应有有效的 uidgivenNamesnmail。新用户如果仍处于首次修改密码状态,应先在 FreeIPA 中完成密码修改,再尝试 Gitea 登录。

4.2 先验证 LDAP 查询

在能访问 IPA 的客户端安装 ldap-utils,使用应用查询账户测试。下面的 -W 输入绑定账户密码,不是登录用户密码:

bash
1
2
3
4
5
6
LDAPTLS_CACERT=/etc/ipa/ca.crt ldapsearch \ -H ldaps://ipa.lab.example.com:636 \ -x -D 'uid=gitea-bind,cn=sysaccounts,cn=etc,dc=lab,dc=example,dc=com' -W \ -b 'cn=users,cn=accounts,dc=lab,dc=example,dc=com' \ '(&(objectClass=posixAccount)(uid=yourname)(memberOf=cn=gitea-users,cn=groups,cn=accounts,dc=lab,dc=example,dc=com)(!(nsAccountLock=TRUE)))' \ dn uid givenName sn mail memberOf

这里应返回指定用户的 DN 与相关属性。若能连接但没有结果,检查搜索基准、组成员关系、账户锁定状态及过滤器,不必先去修改 TLS。

客户端查询成功后,还要确认 Gitea Pod 的 DNS 与网络能到达同一 IPA 地址。宿主机的 CA、hosts 和路由不会全部自动传入容器,最终应以 Gitea 认证源测试或实际登录时的日志为准。

4.3 添加 Gitea 认证源

使用本地管理员进入“站点管理 → 认证源 → 添加认证源”。按 Gitea LDAP 认证文档选择 LDAP via BindDN,填写以下示例:

字段 配置
认证名称 FreeIPA
安全协议 LDAPS
主机 ipa.lab.example.com,不加 URL scheme
端口 636
跳过 TLS 验证 不勾选
Bind DN uid=gitea-bind,cn=sysaccounts,cn=etc,dc=lab,dc=example,dc=com
Bind Password 前面创建的查询账户密码
User Search Base cn=users,cn=accounts,dc=lab,dc=example,dc=com
Username Attribute uid
First Name Attribute givenName
Surname Attribute sn
E-mail Attribute mail
Admin Filter 初次配置留空,不自动授予站点管理员
认证源启用 勾选

User Filter 填写:

text
1
(&(objectClass=posixAccount)(uid=%[1]s)(memberOf=cn=gitea-users,cn=groups,cn=accounts,dc=lab,dc=example,dc=com)(!(nsAccountLock=TRUE)))

%[1]s 是 Gitea 替换登录名的占位符,不能照搬 Nextcloud 的 %uidmemberOf 限制可登录用户范围,nsAccountLock 排除锁定用户。示例从直接加入 gitea-users 的用户开始验证,嵌套组行为要结合自己的目录实际查询结果确认。

如果允许用户名或邮箱登录,可将 (uid=%[1]s) 换成:

text
1
(|(uid=%[1]s)(mail=%[1]s))

Username Attribute 仍使用 uid,避免以邮箱登录时生成另一套 Gitea 用户名。此 LDAP 配置提供账号密码认证,没有配置浏览器 Kerberos 单点登录。

4.4 用户同步与仓库权限

可以在认证源中启用用户同步。首次启用前先用 ldapsearch 确认过滤器范围,避免把整个目录中的用户全部导入。保存认证源不会保证用户列表立即刷新,定时同步的实际执行情况可在 Gitea 管理任务与日志中查看。

IPA 用户组在这里用于限制谁能够认证。Gitea 的组织、团队、仓库读写权限仍需配置;如果需要组到团队的同步映射,应另外配置并验证,不能只创建一个同名 IPA 组就认为权限已经对应。

实验室项目仓库放在组织下,按项目建立团队并分配读写权限。成员加入或退出项目时修改团队成员;重要分支按需配置保护规则,通过 Pull Request 合并修改。

本地管理员使用单独的用户名,普通用户通过 FreeIPA 认证创建 Gitea 账户,避免预先注册同名本地账号造成认证源混淆。

五、配置 Git 客户端

5.1 使用 SSH 克隆

用户先通过 FreeIPA 认证登录 Gitea,再在“用户设置 → SSH / GPG 密钥”中添加自己的 SSH 公钥。已有密钥可直接使用,无需重复生成;没有密钥时可创建:

bash
1
ssh-keygen -t ed25519 -C 'your-email@example.com'

仅将 .pub 文件内容添加到 Gitea。然后测试 SSH 认证:

bash
1
ssh -T -p 22222 git@git.lab.example.com

服务端指纹可在控制节点查询:

bash
1
2
sudo k3s kubectl -n gitea exec deployment/gitea -- \ sh -c 'for key in /data/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$key"; done'

首次连接先核对服务端 SSH 主机密钥指纹。Gitea 成功识别用户后会返回认证成功、不提供交互式 shell 的提示;这与普通服务器 SSH 登录不同。

先在 Gitea 网页中用 IPA 成员创建私有仓库 example-repo,勾选初始化 README。仓库所有者选择该用户,下面的 yourname 改成网页显示的实际账户名。克隆地址为:

bash
1
git clone ssh://git@git.lab.example.com:22222/yourname/example-repo.git

在克隆得到的测试目录中提交并推送,客户端应已配置自己的 Git 姓名和邮箱:

bash
1
2
3
4
5
6
7
cd example-repo git config user.name 'Your Name' git config user.email 'your-email@example.com' printf 'Gitea deployment check\n' > deployment-check.txt git add deployment-check.txt git commit -m 'Add deployment check' git push

在网页确认新提交和文件可见。连接用户名使用 git,Gitea 根据公钥识别实际账户。FreeIPA 网页登录成功,不会自动把 IPA 中的 SSH 公钥导入 Gitea;本文没有配置这类同步。

5.2 使用 HTTPS 克隆

不想单独开放 SSH 时,也可以使用已有 HTTPS 入口:

bash
1
git clone https://git.lab.example.com:8443/yourname/example-repo.git example-repo-https

需要鉴权时,按站点设置使用账号凭据或个人访问令牌。启用双因素认证等场景应使用令牌,并按需要授予仓库权限。不要将密码或令牌嵌入 URL,以免进入 shell 历史和 Git remote 配置。

若需要同时检查 HTTPS 写入,在 example-repo-https 目录修改测试文件,提交并执行 git push,按提示输入账号与访问令牌;再在 SSH 克隆目录执行 git pull --ff-only,确认两种入口访问同一仓库。

HTTPS 访问依赖公共 CA 证书;Git SSH 使用 SSH 主机密钥。浏览器证书续期不会替换 SSH 主机密钥,两者分别维护。

六、常见问题与备份

6.1 LDAP 报证书错误

遇到 certificate signed by unknown authority,检查 IPA CA 是否进入 Gitea 使用的证书库、initContainer 是否成功,以及 CA 更新后是否重建了 Pod。

如果错误是名称不匹配,检查认证源 Host 是否为证书包含的 IPA 域名。直接用内网 IP 连接,不一定满足证书名称校验。公共泛域名证书只配置在 Traefik 上时,也不会改变 FreeIPA LDAPS 返回的证书。

6.2 网页能打开,SSH 连接失败

按客户端、路由器、Service、Pod 的顺序检查端口:

bash
1
2
3
4
ssh -vv -T -p 22222 git@git.lab.example.com sudo k3s kubectl -n gitea get svc gitea-ssh -o yaml sudo k3s kubectl -n gitea get endpointslice \ -l kubernetes.io/service-name=gitea-ssh

连接超时优先检查 DNS、路由器映射、防火墙及 ServiceLB;收到 Permission denied (publickey) 则说明已经进入 SSH 认证阶段,应检查客户端实际提供的公钥及 Gitea 账户关联。

若网页展示的克隆端口仍不正确,修改 GITEA__server__SSH_PORT 并重建 Pod。修改该变量只改变展示地址,路由器和 Service 映射需要单独一致。

6.3 备份数据库与应用文件

安装完成后,应同时备份 PostgreSQL 数据库和 Gitea 的完整 /data,具体方式可参考 Gitea 备份恢复文档。数据库保存用户、权限和认证源,文件目录保存仓库、附件、应用配置及 SSH 主机密钥,两部分应在一致的停写窗口内取得。

认证源绑定密码由 Gitea 加密保存,备份还需要包含 SECRET_KEY 及其可能引用的文件。缺少该密钥时,数据库中的认证配置可能无法解密。包含密钥和凭据的备份应存放在受限目录,并定期验证能否恢复。

完成前面的登录与推送测试后,在可中断服务的时间重建应用 Pod,验证持久化:

bash
1
2
3
sudo k3s kubectl -n gitea rollout restart deployment/gitea sudo k3s kubectl -n gitea rollout status deployment/gitea --timeout=300s sudo k3s kubectl -n gitea get pvc

重新登录,检查认证源、测试仓库与提交,客户端执行 git fetch 并核对 SSH 主机指纹未变化。再用未加入 gitea-users 的 IPA 测试用户验证拒绝登录。组织项目还需分别用有写权限和只读成员测试推送结果。

参考

手机扫码阅读
本文作者: 有次元袋的 tiger
本文链接: https://www.superheaoz.top/2026/09/61943/
版权声明: 本站点所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 我的个人天地