距离上次更新本文已经过去了 235 天,文章部分内容可能已经过时,请注意甄别

1. 跟着文档走

gitea 的安装比较简单,直接使用官方文档中的 docker-compose 文件即可。如果想实现 ssh 容器直通,需要对这个 docker-compose 文件做一定修改。

如果你还没有安装 docker,参考本站教程 linux 安装 docker

gitea 的官方文档上有关于 docker 容器 ssh 直通的教程,但是写的不够清晰,有些问题我没有搞懂。本文基于我的折腾记录和 docker 安装的 gitea 1.21.4 文档

使用 Docker 安装 | Gitea Documentation

image.png

首先是跟着文章里面的步骤做,先创建一个 git 子用户。wsl 中创建子用户的命令参考本站博客,ubuntu 下使用 adduser 命令来添加。

bash
1
sudo adduser git

注意创建的 git 用户的 uid 和 gid 是可能不是 1000,可以用 id 用户名的方式查看信息

plaintext
1
2
$ id git
uid=1002(git) gid=1002(git) groups=1002(git)

为了保证权限一致,docker-compose 中的环境变量需要对应修改。

yaml
1
2
3
environment:
- USER_UID=1001
- USER_GID=1001

还需要新增一个路径映射,在子用户 git 的家目录下创建一个.ssh 目录。

plaintext
1
- /home/git/.ssh/:/data/git/.ssh

注意:为了避免文件读写权限问题,我建议在创建 git 子用户后,在该子用户中操作 docker-compose 和新建 gitea 的映射文件夹,这样能保证 git 用户和 gitea 容器一定能访问到文件夹且具有权限。

在 git 用户中执行如下命令,出现的提示框全部回车即可。因为 git 用户是新创建的,必须把用户 git 加入 sudoers 文件中才能执行 sudo 命令,具体可以参考博客中第八点的介绍。

bash
1
sudo -u git ssh-keygen -t rsa -b 4096 -C "Gitea Host Key"

随后执行如下命令,即把 /home/git/.ssh/id_rsa.pub 写入 /home/git/.ssh/authorized_keys 文件。执行完毕后请不要再手动修改 authorized_keys 文件。

bash
1
echo "$(cat /home/git/.ssh/id_rsa.pub)" >> /home/git/.ssh/authorized_keys

还需要创建一个脚本来执行 ssh 信息转发

plaintext
1
sudo vim /usr/local/bin/gitea

写入如下内容,可以通过 CTRL+SHIFT+V 直接粘贴。这里假设你将 gitea 容器的 22 端口转发到宿主机的 2222 端口(如果你的宿主机映射端口不同,可以修改脚本中的端口号)

plaintext
1
ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"

写入脚本后,一定要把这个文件添加可执行权限

plaintext
1
sudo chmod 777 /usr/local/bin/gitea

因为 ssh 容器直通都是本机处理的操作,所以我们可以在 docker-compose 中端口映射的时候限制来源 IP 地址为本地回环地址,这样就能保证只有宿主机中能访问 2222 端口到 gitea 中,而 2222 端口无法直接被外界访问。

yaml
1
2
3
ports:
# [...]
- "127.0.0.1:2222:22"

gitea 的 ssh 直通流程

配置完毕 ssh 直通后,git 操作流程如下:

  1. 用户使用 git@IP地址访问主机,默认访问 22 端口;
  2. 主机验证 git 用户下.ssh/authorized_keyscommand 开头的公钥中,发现用户公钥;
  3. 主机执行 command 指定的脚本,将此次请求的信息转发给 gitea 容器的 ssh 端口;
  4. gitea 容器执行 ssh 请求处理;

如果不使用容器直通,你可以选择用 https 来进行 git 操作,或者在 ssh 使用时添加端口号。二者都会比直接使用 ssh 麻烦一些。

2. 安装 ssh 服务

另外,默认情况下 wsl 中是没有 ssh 服务的,你会发现 22 端口无人使用

plaintext
1
2
[root:~]# netstat -nltp | grep 22
tcp 0 0 127.0.0.1:2222 0.0.0.0:* LISTEN 2816/docker-proxy

需要安装一下 ssh 服务

bash
1
2
sudo apt install -y openssh-server
sudo systemctl start sshd

使用如下命令查看服务状态以及是否启用了开机自启

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root:~]# systemsystemctl status sshd
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2024-02-07 14:59:06 CST; 9min ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 5202 (sshd)
Tasks: 1 (limit: 9527)
Memory: 1.7M
CGroup: /system.slice/ssh.service
└─5202 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

Feb 07 14:59:06 wsl-ubuntu systemd[1]: Starting OpenBSD Secure Shell server...
Feb 07 14:59:06 wsl-ubuntu sshd[5202]: Server listening on 0.0.0.0 port 22.
Feb 07 14:59:06 wsl-ubuntu sshd[5202]: Server listening on :: port 22.
Feb 07 14:59:06 wsl-ubuntu systemd[1]: Started OpenBSD Secure Shell server.
[root:~]# sudo systemctl is-enabled sshd
alias
[root:~]# sudo systemctl is-enabled ssh
enabled

此时再看看 22 端口,就有人干活了,sshd 服务启动成功

plaintext
1
2
3
4
[root:~]# netstat -nltp | grep 22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 5202/sshd: /usr/sbi
tcp 0 0 127.0.0.1:2222 0.0.0.0:* LISTEN 2816/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 5202/sshd: /usr/sbi

3.web 界面添加用户 ssh 公钥

随后就是和 github 一样的操作, 在 gitea 的 web 页面添加用户的公钥。

【Linux】如何使用 ssh 密钥配置 git

image.png

添加完毕后,检查一下 git 用户里面的 /home/git/.ssh/authorized_keys 文件是否有变动,文件应该如下格式,会有一个 command= 存放了你刚刚在 gitea web 页面添加的用户公钥。

plaintext
1
2
3
4
ssh-rsa <Gitea Host Key>

## other keys from users
command="/usr/local/bin/gitea --config=/data/gitea/conf/app.ini serv key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty <user pubkey>

文档中关于这一块的描述不够清楚(我感觉是机翻的问题)

原文:重要提示:来自 git 用户的公钥需要 “按原样” 添加,而通过 Gitea 网络界面添加的所有其他公钥将以 command="/app [...] 作为前缀。

其实这个说明的意思是,默认情况下的 authorized_keys 文件中应该只有下面的内容(即 “按原样” 添加),而 gitea web 页面添加的其他公钥应该都是以 command=" 作为前缀,自动添加到 authorized_keys 文件之后的。

plaintext
1
ssh-rsa <Gitea Host Key>

说白了就是,在执行完毕上文提到的将 /home/git/.ssh/id_rsa.pub 文件的内容写入 /home/git/.ssh/authorized_keys 的操作后,我们就不要手动修改 authorized_keys 这个文件了!如果出现问题,再依照文档中的这个提示检查该文件中的公钥格式是否正确。

官网文档中还提到了下面几个注意事项,我们全都不用管!只要你没有修改过配置文件和 gitea 容器中的环境,这些配置项都是默认情况下就 OK 了的。

image.png

4. 验证是否直通成功

尝试验证 ssh 是否成功,这里的 ip 是 wsl 的本机 ip,可以在 wsl 中通过 ifconfig 命令查看。

plaintext
1
ssh -T git@172.26.39.91

如果出现下面的情况,说明 22 端口没有被成功开放,请检查:

  • 宿主机中的 22 端口是否已经配置了 sshd 服务,并正常监听 22 端口;
  • 在 web 页面添加的用户公钥是否添加到了 /home/git/.ssh/authorized_keys 文件中;
  • /usr/local/bin/gitea 脚本中的命令无误。
plaintext
1
2
3
4
5
6
7
PS D:\test-git> git clone git@172.26.39.91:musnows/test-action.git
Cloning into 'test-action'...
ssh: connect to host 172.26.39.91 port 22: Connection refused
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

如果看到了下面的内容,可以说明我们 wsl 中的的 ssh 服务已经成功启动了,但是没有成功通过脚本验证 git 用户。

plaintext
1
2
3
4
5
6
7
PS D:\test-git> ssh -T git@172.26.39.91
The authenticity of host '172.26.39.91 (172.26.39.91)' can't be established.
ED25519 key fingerprint is SHA256:xRPtWVSIsHrqmP3VaBD+ZR24nE6SWmgjWUYENN0IfB8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.26.39.91' (ED25519) to the list of known hosts.
bash: line 1: /usr/local/bin/gitea: Permission denied

这是因为我们的 git 用户没有办法执行 /usr/local/bin/gitea 脚本,还记得吗,这个脚本是通过 sudo 创建的,默认情况下是一个文本文件,且只有 root 用户有权限访问

plaintext
1
2
[root:~]# ll /usr/local/bin/gitea
-rw-r--r-- 1 root root 109 Feb 7 14:47 /usr/local/bin/gitea

解决办法很简单,将其权限改成 777 即可。

plaintext
1
2
3
[root:~]# chmod 777 /usr/local/bin/gitea
[root:~]# ll /usr/local/bin/gitea
-rwxrwxrwx 1 root root 109 Feb 7 14:47 /usr/local/bin/gitea*

此时再次测试,发现成功直通 gitea 容器内 ssh!这里会显示你在 web 页面中添加的 ssh 密钥的名字 user from windows

plaintext
1
2
3
4
PS D:\test-git> ssh -T git@172.26.39.91
Warning: Permanently added '[127.0.0.1]:2222' (ED25519) to the list of known hosts.
Hi there, musnows! You've successfully authenticated with the key named user from windows, but Gitea does not provide shell access.
If this is unexpected, please log in with password and setup Gitea under another user.

再试试能不能通过 ssh 克隆仓库,搞定!

plaintext
1
2
3
4
5
6
7
8
PS D:\test-git> git clone git@172.26.39.91:musnows/test-action.git
Cloning into 'test-action'...
remote: Enumerating objects: 80, done.
remote: Counting objects: 100% (80/80), done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 80 (delta 22), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (80/80), 56.15 KiB | 9.36 MiB/s, done.
Resolving deltas: 100% (22/22), done.

5.docker-compose 文件

下面给出本文所用的 gitea 容器 docker-compose 文件,只在官方文档所提供的版本上做了少量修改。

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
version: "3"

networks:
gitea:
external: false

services:
server:
image: gitea/gitea:1.21.4
container_name: gitea
environment:
- USER_UID=1001
- USER_GID=1001
restart: always
networks:
- gitea
volumes:
- /home/git/data:/data
- /home/git/.ssh/:/data/git/.ssh
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "30000:3000"
- "127.0.0.1:2222:22"

注意,在初始化 gitea 的时候不要修改 web 界面和 ssh 的监听端口(对应的是容器内的端口),否则上文的 ssh 直通可能会失败!

The end

如果有疑问,欢迎在评论区交流。

相关参考:如何通过 Docker 搭建 Gitea 并配置 SSL 和 SSH 直通 - 莫乔多博客