AlmaLinux 使用nginx搭建透明代理

前期准备

一台海外服务器、一个DNSPod账号、一个国内可以正常访问的域名,同时需要对Linux有操作基础,至少会使用ssh连接服务器。

由于DNS解析需要一定时间,建议部署前,提前在DNSPod将用于连接代理的域名指向海外服务器IP,并为该域名申请免费的SSL证书。

这里推荐DNSPod,兼顾海内外的解析速度,有专业能力的用户可以随意。


部署nginx

该方案利用nignx作为前端完成SSL加密,并自动分流http2与http1.1,连接trojan时应仅开启alpn的h2选项,不然会无法连接。


1.1 下载与安装nginx

· 添加nginx下载源

cat >> /etc/yum.repos.d/nginx.repo << -'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
-EOF

· 安装nginx-1.22.1

dnf install -y nginx-1.22.1 unzip iptables-services

1.2 编辑nginx配置文件

· 备份nginx原始配置文件

mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak

· 新建nginx配置文件

cat >> /etc/nginx/nginx.conf << -'EOF'
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;

error_log /data/wwwlogs/error_nginx.log crit;
pid       /var/run/nginx.pid;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
}

stream {
    log_format proxy '$remote_addr - [$time_local] '
                     '$ssl_protocol/$ssl_cipher $ssl_alpn_protocol $ssl_server_name '
                     '$status $bytes_sent $bytes_received';

    map $ssl_alpn_protocol $proxy_alpn_protocol {
        h2 127.0.0.1:8080;
        default 127.0.0.1:8081;
    }

    server {
        listen 443 ssl reuseport;

        access_log /data/wwwlogs/access_nginx.log proxy;

        ssl_alpn h2 http/1.1;
        ssl_certificate /data/ssl/trojan.pem;
        ssl_certificate_key /data/ssl/trojan.key;
        ssl_session_cache shared:SSL:16m;
        ssl_session_tickets off;
        ssl_session_timeout 1440m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
        ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256;
        ssl_preread on;

        proxy_protocol on;
        proxy_pass $proxy_alpn_protocol;
    }
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    server_names_hash_bucket_size 128;
    client_header_buffer_size 32k;
    large_client_header_buffers 4 32k;
    client_max_body_size 1024m;
    client_body_buffer_size 10m;
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    server_tokens off;
    tcp_nodelay on;

    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;
    fastcgi_intercept_errors on;

    gzip on;
    gzip_buffers 16 8k;
    gzip_comp_level 6;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_proxied any;
    gzip_vary on;
    gzip_types
        text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
        text/javascript application/javascript application/x-javascript
        text/x-json application/json application/x-web-app-manifest+json
        text/css text/plain text/x-component
        font/opentype application/x-font-ttf application/vnd.ms-fontobject
        image/x-icon;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";

    proxy_set_header X-Real-IP $proxy_protocol_addr;
    proxy_set_header X-Forwarded-For $proxy_protocol_addr;

    log_format basic '$remote_addr - [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';

    server {
        listen 80 default_server reuseport;
        listen 127.0.0.1:8081 default_server reuseport proxy_protocol;
        listen 127.0.0.1:8082 default_server reuseport proxy_protocol http2;
        server_name 0.0.0.0;

        set_real_ip_from 127.0.0.1;
        real_ip_header proxy_protocol;

        charset utf-8;

        access_log /data/wwwlogs/fallback_nginx.log basic;

        location / {
            return 403;
        }

        location = /favicon.ico { 
            log_not_found off; 
        }

        location = /robots.txt {
            log_not_found off;
        }
    }

    include /etc/nginx/conf.d/*.conf;
}
-EOF

1.3 配置SSL证书

· 创建SSL证书目录

mkdir -p /data/ssl

· 添加证书与秘钥

将申请的证书文件与秘钥文件改名为trojan.pem、trojan.key,并放置于/data/ssl目录,如果有运维基础的话,推荐使用acme.sh自动部署


1.4 配置nginx日志

· 创建LOG日志目录

mkdir -p /data/wwwlogs

· 配置日志文件自动切割

cat >> /etc/logrotate.d/nginx << -'EOF'
/data/wwwlogs/*nginx.log {
  daily
  rotate 7
  missingok
  dateext
  compress
  notifempty
  sharedscripts
  postrotate
    [ -e /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
  endscript
}
-EOF

上述示例只会保留7日的日志,可以根据实际需求修改rotate的数值更改保留天数

access_nginx.log 会记录通过443端口访问的全部请求
fallback_nginx.log 会记录trojan回落的请求


1.5 添加蜜罐站点 [可选]

在/etc/nginx/conf.d目录下添加一个站点配置文件,绑定连接trojan的域名,从而创建蜜罐站点,这样通过查看蜜罐站点的日志文件,即可获知哪些IP访问过该蜜罐。

执行 vi /etc/nginx/conf.d/honeypot.conf 命令,输入以下内容后保存

server {
        listen 80;
        listen 127.0.0.1:8081 proxy_protocol;
        listen 127.0.0.1:8082 proxy_protocol http2;
        server_name 1.1.1.1.nip.io;

        access_log /data/wwwlogs/honeypot_nginx.log basic;

        set_real_ip_from 127.0.0.1;
        real_ip_header proxy_protocol;

        charset utf-8;

        if ($server_port = 80){
            return 301 https://$server_name$request_uri;
        }

        location / {
            return 503;
        }
}

需要将server_name的值更改为连接trojan时使用的域名

示例中通过返回503状态,将蜜罐伪装成了一个超载的网站,也可以将return 503替换为proxy_pass http://ip:port反代其它web服务


1.6 启动nignx服务

systemctl start nginx
systemctl enable nginx

此时nginx已经启动,但还需要通过xray部署trojan才能使用


部署trojan

2.1 下载与安装xray

curl -L https://github.com/XTLS/Xray-core/releases/download/v1.6.1/Xray-linux-64.zip -o Xray-linux-64-1.6.1.zip
unzip Xray-linux-64-1.6.1.zip xray -d /usr/local/bin

2.2 创建配置文件

mkdir -p /etc/xray
vi /etc/xray/config.json

输入以下内容后保存

{
    "log": {
        "access": "none",
        "error": "/etc/xray/error.log",
        "loglevel": "error"
    },
    "dns": {
        "servers": [
            "8.8.8.8",
            "208.67.222.222"
        ]
    },
    "inbounds": [
        {
            "port": 8080,
            "protocol": "trojan",
            "settings": {
                "clients": [
                    {
                        "password":"123456",
                        "email": ""
                    }
                ],
                "fallbacks": [
                    {
                        "dest": 8082,
                        "xver": 2
                    }
                ]
            },
            "streamSettings": {
                "network": "tcp",
                "security": "none",
                "sockopt": {
                    "tcpFastOpen": false,
                    "domainStrategy": "UseIP",
                    "acceptProxyProtocol": true,
                    "tcpcongestion": "bbr"
                }
            }
        }
    ],
    "outbounds": [
        {
            "protocol": "freedom"
        }
    ]
}

其中仅需将password项的123456修改为自己的密码即可


2.3 创建trojan服务

cat >> /usr/lib/systemd/system/xray.service << -'EOF'
[Unit]
Description=xray service
Documentation=https://xtls.github.io
After=network.target nss-lookup.target

[Service]
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
ExecStart=/usr/local/bin/xray run -c /etc/xray/config.json
Restart=on-failure
RestartSec=10s
LimitNOFILE=infinity

[Install]
WantedBy=multi-user.target
-EOF

· 关闭SELinux

setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

· 启动xray服务

systemctl start xray
systemctl enable xray

配置Linux

3.1 关闭FirewallD服务

systemctl stop firewalld
systemctl disable firewalld

3.2 配置iptables防火墙

vi /etc/sysconfig/iptables

修改防火墙配置文件规则如下

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

开启防火墙

systemctl enable iptables
systemctl restart iptables

(注:如果你的服务器提供商在web管理页面有防火墙,应前往开启TCP的443端口)


3.3 优化内核参数

echo -e '\n\nulimit -SHn 65535\n' >> /etc/profile && source /etc/profile

echo "*     soft   nofile    65535
*     hard   nofile    65535
*     soft   nproc     65535
*     hard   nproc     65535
*     soft   core      65535
*     hard   core      65535
*     hard   memlock   unlimited
*     soft   memlock   unlimited
">/etc/security/limits.conf

cat >> /etc/sysctl.conf << -'EOF'
fs.file-max = 65535
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 1024 65500
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 262144
net.core.netdev_max_backlog = 262144
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_notsent_lowat = 16384
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
-EOF

sysctl -p

至此,一台透明代理服务器搭建完成


xray客户端socks5配置示例

{
    "log": {
        "access": "none",
        "error": "/etc/xray/error.log",
        "loglevel": "error"
    },
    "inbounds": [
        {
            "port": 10800,
            "listen": "0.0.0.0",
            "protocol": "socks",
            "settings": {
                "auth": "noauth",
                "udp": true,
                "ip": "0.0.0.0"
            },
            "streamSettings": {
                "network": "tcp",
                "sockopt": {
                    "tcpcongestion": "bbr"
                }
            }
        }
    ],
    "outbounds": [
        {
            "protocol": "trojan",
            "settings": {
                "servers": [
                    {
                        "address": "连接trojan的域名或IP",
                        "port": 443,
                        "password": "连接trojan的密码"
                    }
                ]
            },
            "streamSettings": {
                "network": "tcp",
                "security": "tls",
                "tlsSettings": {
                    "allowInsecure": false,
                    "serverName": "连接trojan的域名",
                    "fingerprint": "chrome",
                    "alpn": "h2"
                },
                "sockopt": {
                    "tcpcongestion": "bbr"
                }
            }
        }
    ]
}

支持trojan协议的客户端,请参考:
https://www.v2ray.com/awesome/tools.html