Skip to content

Instantly share code, notes, and snippets.

@myfingerhurt
Created October 2, 2021 13:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myfingerhurt/54921bb075b5974b7f98955d8a8e7951 to your computer and use it in GitHub Desktop.
Save myfingerhurt/54921bb075b5974b7f98955d8a8e7951 to your computer and use it in GitHub Desktop.
reverse proxy configuration guide for v2ray behind a http-proxy and nginx

This should be working on most of enterprise network environment which usually behinds a http-proxy.

  • Network Topology
Services(port:8888) <--> Bridge-Node(Win) <-->  HTTP-Proxy(Crop.) <-->  Protal-Node(VPS) <--> V2RayN(7890) <--> Client(curl)
                         Vmess                                          Vmess                 Vmess
  • C:\Windows\System32\drivers\etc\hosts
# localhost name resolution is handled within DNS itself.
#  127.0.0.1       localhost
#  ::1             localhost
   127.0.0.1       private.cloud.com       # frp
  • Verify(On Client)
curl -v -x socks5h://127.0.0.1:7890 private.cloud.com:8888
*   Trying 127.0.0.1:7890...
* TCP_NODELAY set
* SOCKS5 communication to private.cloud.com:8888
* SOCKS5 connect to private.cloud.com:8888 (remotely resolved)
* SOCKS5 request granted.
* Connected to 127.0.0.1 (127.0.0.1) port 7890 (#0)
> GET / HTTP/1.1
> Host: private.cloud.com:8888
> User-Agent: curl/7.67.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Connection: close
< Location: https://private.cloud.com:8888
<
* Closing connection 0
  • Full Configuration Files
Configuration for Bridge-Node, Click to expand! This is for http80 port, if you are going to use 443, uncomment the tls part.
{
    "policy":
    {
        "system":
        {
            "statsOutboundUplink": true,
            "statsOutboundDownlink": true
        }
    },
    "log":
    {
        //"access": "v2ray_access.log",
        "access": "",
        "error": "",
        "loglevel": "debug"
    },
    "reverse":
    {
        // 这是 A 的反向代理设置,必须有下面的 bridges 对象
        "bridges": [
            {
                "tag": "bridge", // 关于 A 的反向代理标签,在路由中会用到
                "domain": "pc1.localhost" // 一个域名,用于标识反向代理的流量,不必真实存在,但必须跟下面 B 中的 reverse 配置的域名一致
            }
        ]
    },
    "inbounds": [
        {
            "tag": "pre-proxy",
            "listen": "127.0.0.1",
            "port": 8081,
            "protocol": "dokodemo-door",
            "settings":
            {
                "network": "tcp",
                "address": "your.domain.com",
                "port": 80
            }
        }

    ],
    "outbounds": [
        {
            //A连接B的outbound
            "tag": "tunnel", // A 连接 B的 outbound 的标签,在路由中会用到
            "protocol": "vmess",
            "settings":
            {
                "vnext": [
                    {
                        "address": "127.0.0.1",
                        "port": 8081,
                        "users": [
                            {
                                "id": "c299cc7e-89e4-439c-ccdf-a53cd597306d",
                                "alterId": 1,
                                "security": "auto"
                            }
                        ]
                    }
                ]
            },
            "streamSettings":
            {
                "network": "ws",
              //"security": "tls",
              //"tlsSettings":
              //{
              //    "serverName": "your.domain.com"
              //},
                "wsSettings":
                {
                    "path": "/your_path",
                    "headers":
                    {
                        "Host": "your.domain.com"
                    }
                }
            },
            "mux":
            {
                "enabled": false,
                "concurrency": -1
            }
        },
        { // 另一个 outbound,最终连接私有网盘
            "protocol": "freedom",
            "settings":
            {
                //       "redirect": "127.0.0.1:7890"
            },
            "tag": "out"
        },
        {
            "tag": "http-out",
            "protocol": "http",
            "settings":
            {
                "servers": [
                    {
                        "address": "127.0.0.1", //服务器IP
                        "port": 7890, //服务器端口
                        "users": [
                            {
                                "user": "", //你的用户名.
                                "pass": ""  //你的密码
                            }
                        ]
                    }
                ]
            }
        }
    ],
    "routing":
    {
        "rules": [
            {
                // 配置 A 主动连接 B 的路由规则
                "type": "field",
                "inboundTag": [
                    "bridge"
                ],
                "domain": [
                    "full:pc1.localhost"
                ],
                "outboundTag": "tunnel"
            },
            {
                // 反向连接访问私有网盘的规则
                "type": "field",
                "inboundTag": [
                    "bridge"
                ],
                "outboundTag": "out"
            },
            {
                "type": "field",
                "inboundTag": "pre-proxy",
                "outboundTag": "http-out"
            }
        ]
    }
}
Configuration for Protal-Node, Click to expand! This v2ray server rely on nginx HAProxy.
{
    "log":
    {
        "access": "/var/log/v2ray_access.log",
        "error": "none",
        "loglevel": "warning"
    },
    "api":
    {
        "services": [
            "HandlerService",
            "LoggerService",
            "StatsService"
        ],
        "tag": "api"
    },
    "reverse":
    {
        "portals": [
            {
                "tag": "portal",
                "domain": "pc1.localhost"
            }
        ]
    },
    "inbounds": [
        {
            "listen": "127.0.0.1",
            "port": 62789,
            "protocol": "dokodemo-door",
            "settings":
            {
                "address": "127.0.0.1"
            },
            "tag": "api"
        },
        {
            "listen": "0.0.0.0",
            "port": 50117,
            "protocol": "vmess",
            "settings":
            {
                "clients": [
                    {
                        "id": "c299cc7e-89e4-439c-ccdf-a53cd597306d",
                        "alterId": 1
                    }
                ],
                "disableInsecureEncryption": false
            },
            "streamSettings":
            {
                "network": "ws",
                "security": "none",
                "wsSettings":
                {
                    "path": "/50117",
                    "headers": {}
                }
            },
            "tag": "inbound-50117",
            "sniffing":
            {
                "enabled": true,
                "destOverride": [
                    "http",
                    "tls"
                ]
            }
        }
    ],
    "outbounds": [
        {
            "protocol": "freedom",

            "settings": {}
        },
        {
            "protocol": "dns",

            "tag": "dns-out",
            "streamSettings":
            {
                "sockopt":
                {
                    "mark": 255
                }
            }
        },
        {
            "protocol": "blackhole",
            "settings": {},
            "tag": "blocked"
        }
    ],
    "policy":
    {
        "system":
        {
            "statsInboundDownlink": true,
            "statsInboundUplink": true
        }
    },
    "dns":
    {
        "hosts":
        {
            "dns.google": "8.8.8.8"
        },
        "servers": [
            "8.8.8.8",
            "8.8.4.4",
            "1.1.1.1"
        ],
        "tag": "dns_in"
    },
    "routing":
    {
        "rules": [
            {
                "inboundTag": [
                    "api"
                ],
                "outboundTag": "api",
                "type": "field"
            },
            {
                "type": "field",
                "inboundTag": ["dns-in"],
                "outboundTag": "dns-out"
            },
            {
                "type": "field",
                "inboundTag": [
                    "interconn",
                    "inbound-50117"
                ],
                "outboundTag": "portal"
            },
            {
                "type": "field",
                "domain": [
                    "full:private.cloud.com"
                ],
                "outboundTag": "portal"
            },
            {
                "domain": [
                    "domain:google.com",
                    "domain:apple.com",
                    "domain:oppomobile.com"
                ],
                "type": "field",
                "outboundTag": "allowed"
            },
            {
                "outboundTag": "blocked",
                "protocol": [
                    "bittorrent"
                ],
                "type": "field"
            }
        ]
    },
    "stats": {}
}
/etc/nginx/nginx.conf, Click to expand! Supports HTTP80 and HTTPS443 for v2ray. Nginx is sharing with Trojan, MTProxy, Website, and so on.
user  www-data;
worker_processes  auto;
worker_rlimit_nofile 65535;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

include /etc/nginx/modules-enabled/*.conf;
#load_module modules/ngx_stream_geoip_module.so;

events {
	worker_connections 4096;
	# multi_accept on;
}


stream {

	log_format streamlog ' $remote_addr  \t[$time_iso8601] '
                         ' $protocol $status '
                         ' R:$bytes_received T:$bytes_sent $upstream_addr $ssl_preread_server_name';
                        
	#------------------------------
	server {
		listen 80;
        proxy_pass LocalHttp80End;
        proxy_protocol on;
        
        access_log /var/log/nginx/stream_80_access.log streamlog;
        error_log  /var/log/nginx/stream_80_error.log;
    }
	#------------------------------
	server {
		listen           443;
		listen      [::]:443;
		proxy_pass      $ssl_backend;
		proxy_protocol  on; # Key step support HAProxy proxy_protocol
		ssl_preread     on; # preread SNI hostname

		access_log /var/log/nginx/stream_access.log streamlog;
		error_log  /var/log/nginx/stream_error.log; # Health check notifications
	}

	map $ssl_preread_server_name $ssl_backend {
		"~^t\d{0,1}\.domain\.com$" trojan_pre;
		www.ti.com mtproxy;
        
        "~^v\d{0,1}\.domain\.com$" LocalBackEnd;
        "~^r\d{0,1}\.domain\.com$" LocalBackEnd;
        "~^p\d{0,1}\.domain\.com$" LocalBackEnd;
		your.domain.com LocalBackEnd;

		default LocalBackEnd;
	}

    #------------------------------
    upstream trojan_pre {
        server 127.0.0.1:2442;
    }

    server {
        listen localhost:2442 reuseport proxy_protocol;
        proxy_pass trojan;
    }
    
    upstream trojan {
        server 127.0.0.1:2443;
    }
    #------------------------------
    upstream mtproxy {
        server 127.0.0.1:3443;
    }
    
    upstream mtproxy_pre {
        server 127.0.0.1:3445;
    }
    
    server {
        listen localhost:3445 reuseport proxy_protocol;
        #proxy_pass mtproxy1;
        
        # set_real_ip_from 127.0.0.1;
        # real_ip_header proxy_protocol;
        proxy_pass 127.0.0.1:3444;
    }
    
    upstream mtproxy1 {
        server 127.0.0.1:3444;
    }
    #------------------------------
    upstream LocalBackEnd {
        server localhost:1443; # temp server
    }

    #------------------------------

    upstream LocalHttp80End {
        server localhost:2080; # temp server
    }
    #------------------------------
}

http {

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# SSL Settings
	##

    # https://nginx.org/en/docs/http/ngx_http_ssl_module.html
	ssl_protocols TLSv1.2 TLSv1.3; # Dropping TLSv1 TLSv1.1 TLSv1.2 SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;
    
    ##
    # Client IP MAP Settings
    ##
    
    map $http_x_forwarded_for $client_ip {
        # IPv4 addresses can be sent as-is
        ~^[0-9.]+$          "$http_x_forwarded_for";
        default             "$proxy_protocol_addr";
    }

    ##
    # Logging Settings
    ##
    #keyval_zone zone=clients:80m timeout=3600s;
    #keyval $remote_addr:$http_user_agent $seen zone=clients;
    
    #include                 log.conf;

    log_format  main  ' $remote_addr\t[$time_iso8601] '
                      ' $status TX:$body_bytes_sent\t'
					  ' $client_ip\t'
					  ' "$request" '
                      ' "$http_user_agent" '
					  ' "$http_referer" ';
    
    log_format  main2 ' $client_ip:$proxy_protocol_port\t[$time_iso8601] '
                      ' $status T:$body_bytes_sent '
					  ' "$request" $host '
                      ' | pa:$proxy_protocol_addr | cf:$http_cf_connecting_ip | xf:$http_x_forwarded_for | xr:$http_x_real_ip ' ;

    log_format  main3 ' $remote_addr\t[$time_iso8601] '
                      ' $status TX:$body_bytes_sent\t' 
                      ' $http_x_forwarded_for\t'
					  ' $proxy_protocol_addr:$proxy_protocol_port\t'
                      ' $request ' ;
					  

    access_log  /var/log/nginx/access_http.log main;
    error_log   /var/log/nginx/error_http.log;

	##
	# Gzip Settings
	##

	gzip on;

    # https://nginx.org/cn/docs/http/ngx_http_proxy_module.html
    # 1MB = 8000key
      proxy_cache_path        cache
        levels=1:2
        keys_zone=my_cache:32m
        max_size=20g
        inactive=6h
        use_temp_path=off
      ;


    #------------------------------
    
	##
	# Http 80 Host Configs
	##
    
    include /etc/nginx/http80.conf;
    
    #------------------------------

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}
/etc/nginx/http80.conf, Click to expand! HTTP80 redirect
    # ------------------------------------------------
    server {
        listen 127.0.0.1:2080 proxy_protocol;

        server_name ~^(v|r)\d+\.domain\.(com|org)$;     #equals to v1.domain.com v2.domain.com;
        

        location = /robots.txt {
           add_header Content-Type text/plain;
           return 200 "User-agent: *\nDisallow: /\n";
        }
        
        location = / {
           return 204;
        }
        
        access_log /var/log/nginx/access_80_50xxx.log main2;
       
        # Regex for vmess /501xx 
        location ~ "^/(501[\d]{2})$" {
            proxy_pass       http://127.0.0.1:$1;
            proxy_redirect             off;
            proxy_http_version         1.1;
            proxy_set_header Upgrade   $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host      $http_host;
          # Show real IP in v2ray access.log
            proxy_set_header X-Forwarded-For $client_ip;

        }
            

    }
    

    # ------------------------------------------------
    server {
        listen 127.0.0.1:2080 default_server proxy_protocol;
        
        set_real_ip_from 127.0.0.1;

        #server_name _;
        server_name ~^(r\d+|p\d+)\.domain\.(com|org)$;
        
        access_log /var/log/nginx/access_301.log main2;

        return 301 https://$host$request_uri;
    }
/etc/nginx/v2ray-ports.conf, Click to expand! V2ray websocket revers proxy
    access_log /var/log/nginx/access_50xxx.log main2;
   
    # Regex for vmess /501xx 
    location ~ "^/(501[\d]{2})$" {
        proxy_pass       http://127.0.0.1:$1;
        proxy_redirect             off;
        proxy_http_version         1.1;
        proxy_set_header Upgrade   $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host      $http_host;
      # Show real IP in v2ray access.log
        proxy_set_header X-Forwarded-For $client_ip;
    }
/etc/nginx/domain.com.comm.conf, Click to expand!
    ssl_certificate /home/ubuntu/.acme.sh/domain.com/fullchain.cer;
    ssl_certificate_key /home/ubuntu/.acme.sh/domain.com/domain.com.key;
    ssl_protocols TLSv1.3;
    ssl_prefer_server_ciphers on;

    ssl_buffer_size 1500;
    add_header Strict-Transport-Security max-age=15768000;

    ssl_stapling off;
    ssl_stapling_verify on;
    ssl_trusted_certificate /home/ubuntu/.acme.sh/domain.com/fullchain.cer;
    
    if ($ssl_protocol = "") { return 301 https://$host$request_uri; }

    location = /robots.txt {
       add_header Content-Type text/plain;
       return 200 "User-agent: *\nDisallow: /\n";
    }

    location = /204 {
       return 204;
    }
/etc/nginx/sites-available/domain.com, Click to expand!
server {

    server_name ~^v\d+\.domain\.com$ ~^r\d+\.domain\.com$;     #equals to v1.domain.com;
    listen 127.0.0.1:1443 ssl http2  proxy_protocol;

    include    /etc/nginx/domain.com.comm.conf;
    
    access_log /var/log/nginx/access_v2ray_domain.com.log main2;
 
    location /ip {
        default_type text/plain;
        return 200 "$remote_addr\n";
    }

    include    /etc/nginx/v2ray-ports.conf;

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment