文章

部署Gitea+Nginx+Xray服务

部署Gitea+Nginx+Xray服务

前言

众所周知部署VLESS+XTLS+Reality时,一般使用一个诸如microsoft.com的域名来进行TLS握手,达到伪装的目的。然而最近越来越多的用户反映,使用别人的域名有可能导致VPS被标记为滥用,体验也不一定稳定。考虑到XTLS已经可以尽可能消除TLS in TLS特征,将域名改成自己建立的网站也仍然能够保留隐蔽性。而对于配置不高的VPS,部署一个Gitea作为自己的网站是一个不错的选择。本文将介绍如何在VPS上部署Gitea+Nginx+Xray服务。

准备

  • 一台VPS,有公网IP,推荐使用Debian/Ubuntu系统,本文将以Debian 13为例
  • 域名,已解析到VPS的IP地址(CloudFlare中必须关闭黄云,否则Xray无法工作)

架构

使用Xray监听443端口,对于Xray认为合法的流量使用Reality握手,否则直接原封不动回落到本地的Nginx服务,实现同一个域名两个用途,同时保持隐蔽性。Nginx监听8001端口,在验证主机名合法后转发给3000端口上的Gitea。

选择:Xray还是sing-box?

Xray和sing-box都支持Reality协议,但在实际使用中,sing-box的性能和稳定性更好一些。然而为了让Nginx日志显示真实访客IP而不是127.0.0.1,必须要让Xray转发proxy protocol给Nginx,而sing-box目前不支持proxy protocol,因此本文选择使用Xray。此外,额外提供了sing-box的配置文件供参考。

部署:Xray

如果你希望使用sing-box,请跳过本节:#

安装

使用以下命令安装Xray,该命令自动适配所有架构:

1
sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install

安装完成后,使用以下命令启动Xray服务(如果脚本没有自动启动的话):

1
sudo systemctl enable --now xray

生成所需内容

使用以下命令生成UUID:

1
xray uuid

使用以下命令生成Reality所需的密钥对:

1
xray x25519

使用以下命令生成Reality所需的shortid:

1
openssl rand -hex 8

记下这几个内容,后续配置中需要使用,且请务必妥善保管,避免泄露。

配置

配置文件在/usr/local/etc/xray/config.json,使用以下命令编辑:

1
sudo vim /usr/local/etc/xray/config.json

输入dd删除全部内容,然后粘贴以下配置(注意将YOUR_UUID、YOUR_PRIVATE_KEY、YOUR_SHORT_ID和YOUR_DOMAIN替换为实际值):

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
{
    "log": {
        "loglevel": "warning"
    },
    "dns": {
        "servers": [
            {
                "address": "https://1.1.1.1/dns-query"
            }
        ]
    },
    "inbounds": [
        {
            "listen": "::",
            "port": 443,
            "protocol": "vless",
            "settings": {
                "clients": [
                    {
                        "id": "YOUR_UUID",
                        "flow": "xtls-rprx-vision"
                    }
                ],
                "decryption": "none"
            },
            "streamSettings": {
                "network": "tcp",
                "security": "reality",
                "realitySettings": {
                    "show": false,
                    "target": "127.0.0.1:8001",
                    "xver": 1,
                    "serverNames": ["YOUR_DOMAIN"],
                    "privateKey": "YOUR_PRIVATE_KEY",
                    "shortIds": ["YOUR_SHORT_ID"]
                }
            },
            "sniffing": {
                "enabled": true,
                "destOverride": ["http", "tls", "quic"]
            }
        }
    ],
    "outbounds": [
        {
            "protocol": "freedom",
            "tag": "direct"
        },
        {
            "protocol": "blackhole",
            "tag": "block"
        }
    ],
    "routing": {
        "domainStrategy": "AsIs",
        "rules": [
            {
                "type": "field",
                "ip": ["geoip:private", "geoip:cn"],
                "outboundTag": "block"
            },
            {
                "type": "field",
                "domain": ["geosite:cn"],
                "outboundTag": "block"
            },
            {
                "type": "field",
                "protocol": ["bittorrent"],
                "outboundTag": "block"
            }
        ]
    }
}

为了防止各种探测,该配置文件默认丢弃部分流量,而常规HTTPS流量将转发到Nginx服务。而xver=1则向Nginx传递了proxy protocol。配置完成后,使用以下命令重启Xray服务:

1
sudo systemctl restart xray

由于此时Nginx服务还没有配置,连不上是正常的。

部署: sing-box(可选)

如果你只需要Xray,请跳过本节:#

如果不在意Nginx日志中全都是127.0.0.1的问题,可以使用sing-box替代Xray,一般认为性能更好。由于共用端口,sing-box和Xray无法同时运行,因此需要先禁用Xray服务:

1
sudo systemctl disable --now xray

安装

使用官方apt仓库:

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo mkdir -p /etc/apt/keyrings &&
   sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc &&
   sudo chmod a+r /etc/apt/keyrings/sagernet.asc &&
   echo '
Types: deb
URIs: https://deb.sagernet.org/
Suites: *
Components: *
Enabled: yes
Signed-By: /etc/apt/keyrings/sagernet.asc
' | sudo tee /etc/apt/sources.list.d/sagernet.sources &&
   sudo apt-get update &&
   sudo apt-get install sing-box # or sing-box-beta

启用服务:

1
sudo systemctl enable --now sing-box

生成所需内容

sing-box生成的原理和Xray是一样的,如果已经生成过了可以跳过。 没有生成过的请使用以下命令生成UUID:

1
sing-box generate uuid

使用以下命令生成Reality所需的密钥对:

1
sing-box generate reality-keypair

使用以下命令生成Reality所需的shortid:

1
openssl rand -hex 8

记下这几个内容,后续配置中需要使用,且请务必妥善保管,避免泄露。

配置

1
vim /etc/sing-box/config.json

用上述方法安装sing-box时会自动创建配置文件/etc/sing-box/config.json,其中含有一个非空的示例配置,编辑时需要按住d全部删掉再粘贴。同样,记得将YOUR_UUID、YOUR_PRIVATE_KEY、YOUR_SHORT_ID和YOUR_DOMAIN替换为实际值:

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
{
    "log": {
        "level": "warn",
        "timestamp": true
    },
    "dns": {
        "servers": [
            {
                "type": "https",
                "tag": "local",
                "server": "1.1.1.1"
            }
        ],
        "strategy": "prefer_ipv4"
    },
    "inbounds": [
        {
            "type": "vless",
            "tag": "vless-in",
            "listen": "::",
            "listen_port": 443,
            "users": [
                {
                    "name": "YOUR_NAME",
                    "uuid": "YOUR_UUID",
                    "flow": "xtls-rprx-vision"
                }
            ],
            "tls": {
                "enabled": true,
                "server_name": "YOUR_DOMAIN",
                "reality": {
                    "enabled": true,
                    "handshake": {
                        "server": "127.0.0.1",
                        "server_port": 8001
                    },
                    "private_key": "YOUR_PRIVATE_KEY",
                    "short_id": ["YOUR_SHORT_ID"]
                }
            }
        }
    ],
    "outbounds": [
        {
            "type": "direct",
            "tag": "direct",
            "domain_resolver": "local"
        }
    ],
    "route": {
        "rules": [
            {
                "action": "sniff"
            },
            {
                "ip_is_private": true,
                "rule_set": ["geoip-cn", "geosite-cn"],
                "action": "reject"
            },
            {
                "protocol": "bittorrent",
                "action": "reject"
            }
        ],
        "rule_set": [
            {
                "type": "remote",
                "tag": "geosite-cn",
                "format": "binary",
                "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs"
            },
            {
                "type": "remote",
                "tag": "geoip-cn",
                "format": "binary",
                "url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
            }
        ],
        "final": "direct"
    }
}

和Xray配置一样,sing-box配置中默认丢弃部分流量,而常规HTTPS流量将转发到Nginx服务。配置完成后,使用以下命令重启sing-box服务:

1
sudo systemctl restart sing-box

部署:Nginx

Nginx用于提供证书和回落到Gitea服务,监听8001端口。在此之前,还需要获取证书,推荐使用Certbot等免费服务。下文将以CloudFlare的DNS 01验证方式为例,介绍如何获取证书。如果使用其他方式获取证书,请参考Certbot官方文档

安装Nginx并申请证书

安装Nginx和Certbot的依赖:

1
2
3
sudo apt update
sudo apt install nginx
sudo apt install python3 python3-dev python3-venv libaugeas-dev gcc

创建Python虚拟环境并安装Certbot:

1
2
3
4
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/local/bin/certbot

安装CloudFlare插件:

1
sudo /opt/certbot/bin/pip install certbot-dns-cloudflare

到CloudFlare网站创建一个API Token,必须开启的权限是该域名下的DNS Write,复制下来(应该为cfat_xxxxxxxxxxxxxxx的形式),保存到任意地方的文件中,内容如下:

1
dns_cloudflare_api_token = cfat_xxxxxxxxxxxxxxx

然后运行

1
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /path/to/your/cloudflare.ini -d YOUR_DOMAIN

这里域名支持通配符(例如*.example.com),可以用多个-d参数指定多个域名。证书将会保存在/etc/letsencrypt/live/YOUR_DOMAIN/目录下。 自动更新证书:

1
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null

配置Nginx

1
sudo vim /etc/nginx/conf.d/reality.conf

粘贴以下内容(注意将YOUR_DOMAIN替换为实际值):

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
# 1. 默认服务器:阻断未知 SNI 和直接 IP 扫描
server {
    # 必须加上 proxy_protocol,因为 Xray 开启 xver: 1 后会无差别发送协议头
    listen 127.0.0.1:8001 ssl proxy_protocol default_server;
    # listen 127.0.0.1:8001 ssl default_server;
    # 拒绝所有非白名单域名的 TLS 握手
    ssl_reject_handshake on;
}

# 2. 真实网站:处理来自 Xray 的合法回落流量
server {
    listen 127.0.0.1:8001 ssl proxy_protocol;
    # listen 127.0.0.1:8001 ssl;
    http2 on;

    server_name YOUR_DOMAIN;

    # 还原访客的真实 IP(用于 Nginx 日志)
    set_real_ip_from 127.0.0.1;
    real_ip_header proxy_protocol;

    # 你的真实 SSL 证书路径(请根据你的实际路径修改)
    ssl_certificate     /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem;

    # TLS 安全套件配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers TLS13_AES_128_GCM_SHA256:TLS13_AES_256_GCM_SHA384:TLS13_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers on;

    # Gitea
    location / {
        proxy_pass http://127.0.0.1:3000;

        # 传递客户端真实 IP 给 Gitea
        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;

        # 支持 WebSocket(Gitea 的实时通知功能需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # 允许上传较大文件(例如代码包、附件)
        client_max_body_size 512M;
    }
}

如果你使用了sing-box,或者Xray配置中没有开启xver: 1,那么需要修改这些行为如下内容:

1
2
3
4
5
6
7
8
9
    # listen 127.0.0.1:8001 ssl proxy_protocol default_server;
    listen 127.0.0.1:8001 ssl default_server;


    # listen 127.0.0.1:8001 ssl proxy_protocol;
    listen 127.0.0.1:8001 ssl;


    # real_ip_header proxy_protocol;

保存后重启Nginx:

1
2
sudo systemctl enable --now nginx
sudo systemctl restart nginx

客户端配置

对于Mihomo内核(注意将YOUR_UUID、YOUR_PUBLIC_KEY、YOUR_SHORT_ID、YOUR_IP和YOUR_DOMAIN替换为实际值):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  - name: proxy
    type: vless
    server: YOUR_IP
    port: 443
    udp: true
    uuid: YOUR_UUID
    flow: xtls-rprx-vision
    packet-encoding: xudp
    tls: true
    servername: YOUR_DOMAIN
    client-fingerprint: chrome
    network: tcp
    reality-opts:
        public-key: YOUR_PUBLIC_KEY
        short-id: "YOUR_SHORT_ID"

对于sing-box内核(注意将YOUR_UUID、YOUR_PUBLIC_KEY、YOUR_SHORT_ID、YOUR_IP和YOUR_DOMAIN替换为实际值):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
    "type": "vless",
    "tag": "proxy",
    "server": "YOUR_IP",
    "server_port": 443,
    "uuid": "YOUR_UUID",
    "flow": "xtls-rprx-vision",
    "packet_encoding": "xudp",
    "tls": {
        "enabled": true,
        "server_name": "YOUR_DOMAIN",
        "utls": {
            "enabled": true,
            "fingerprint": "chrome"
        },
        "reality": {
            "enabled": true,
            "public_key": "YOUR_PUBLIC_KEY",
            "short_id": "YOUR_SHORT_ID"
        }
    }
}

如果可以连接,且访问域名看到502 Bad Gateway,说明Xray和Nginx配置正确。如果无法连接,需要排查VPS是否开启443端口。

安装Gitea

Gitea其实并没有提供官方的一键安装脚本,但可以使用官方提供的二进制文件。下载最新版本的Gitea:

1
2
sudo wget -o /usr/local/bin/gitea https://dl.gitea.com/gitea/1.27.1/gitea-1.27.1-linux-amd64
sudo chmod +x /usr/local/bin/gitea

创建Gitea用户和目录:

1
2
3
4
5
6
7
sudo adduser --system --shell /bin/bash --gecos 'Git Version Control' --group --disabled-password --home /home/git git
sudo mkdir -p /var/lib/gitea/{custom,data,log}
sudo chown -R git:git /var/lib/gitea/
sudo chmod -R 750 /var/lib/gitea/
sudo mkdir -p /etc/gitea
sudo chown root:git /etc/gitea
sudo chmod 770 /etc/gitea

创建Gitea服务文件:

1
sudo vim /etc/systemd/system/gitea.service

写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea/

[Install]
WantedBy=multi-user.target

保存后启动Gitea:

1
sudo systemctl enable --now gitea

无须重启Nginx或者Xray,直接访问https://YOUR_DOMAIN即可看到Gitea的安装界面。

后续步骤

Gitea和GitHub一样,支持使用PGP签名提交,且由于Gitea没有像gh-cli一样的官方命令行工具,因此推荐使用SSH访问。 如果需要让Gitea上的仓库提交使用和GitHub不同的邮件(例如开启了隐藏电子邮件),可以参考以下配置。 在~/.gitconfig中添加:

1
2
[includeIf "hasconfig:remote.*.url:git@YOUR_DOMAIN:*/**"]
    path = ~/.gitconfig-gitea

~/.gitconfig-gitea中添加:

1
2
3
[user]
    name = YOUR_NAME
    email = YOUR_GITEA_EMAIL

如果开启了电子邮件隐藏功能,Gitea会提供一个noreply邮箱地址,使用该邮箱地址即可隐藏真实邮箱,该地址形如:1+YOUR_NAME@noreply.YOUR_DOMAIN

总结

作为托管服务,Gitea本身的流量特征和Xray有一定相似之处,比直接使用microsoft.com等域名更稳定,握手延迟更低,且不容易因为滥用而被封禁,是一个可行又实用的回落方案。

本文由作者按照 CC BY 4.0 进行授权