├── .gitignore ├── haproxy-bridge-server ├── docker-compose.yml └── haproxy-template.cfg ├── v2ray-docker-client ├── docker-compose.yml └── config │ ├── config-template.json │ └── config-template-with-tls.json ├── v2ray-upstream-server ├── docker-compose.yml └── config │ ├── config-template.json │ └── config-template-with-tls.json ├── README.md └── v2ray-install.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .env 3 | .docker 4 | # ignore certificates/keys 5 | **/*.pem 6 | **/*.crt 7 | **/*.key 8 | # ignore generated configs 9 | v2ray-docker-client/config/config.json 10 | v2ray-upstream-server/config/config.json 11 | haproxy-bridge-server/haproxy.cfg 12 | v2ray-data -------------------------------------------------------------------------------- /haproxy-bridge-server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | haproxy: 5 | image: haproxy:lts-bullseye 6 | container_name: haproxy_bridge 7 | restart: always 8 | ports: 9 | - 80:80 10 | - 443:443 11 | - 6543:6543 # stats page 12 | volumes: 13 | - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro 14 | - ./certificate.pem:/usr/local/etc/certificate.pem:ro -------------------------------------------------------------------------------- /v2ray-docker-client/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | v2ray: 5 | image: v2fly/v2fly-core:v5.1.0 6 | container_name: v2ray_client 7 | restart: always 8 | environment: 9 | - v2ray.vmess.aead.forced=false 10 | command: [ "v2ray","run", "-c", "/etc/v2ray/config.json" ] 11 | ports: 12 | - 1081:1081 13 | - 1082:1082 14 | - 1083:1083 15 | - 1084:1084 16 | - 1085:1085 17 | - 1086:1086 18 | - 8118:8118 19 | volumes: 20 | - ./config/:/etc/v2ray/:ro -------------------------------------------------------------------------------- /v2ray-upstream-server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | v2ray: 5 | image: v2fly/v2fly-core:v5.1.0 6 | container_name: v2ray_upstream 7 | restart: always 8 | environment: 9 | - v2ray.vmess.aead.forced=false 10 | command: [ "v2ray","run", "-c", "/etc/v2ray/config.json" ] 11 | ports: 12 | - 80:80 # vmess 13 | - 100:100 # shadowsocks 14 | - 1355:1355 # vless 15 | - 13555:13555 # vless-tls 16 | # - 84:84 17 | # - 85:85 18 | # - 86:86 19 | volumes: 20 | - ./config/:/etc/v2ray/:ro -------------------------------------------------------------------------------- /haproxy-bridge-server/haproxy-template.cfg: -------------------------------------------------------------------------------- 1 | global 2 | user haproxy 3 | log stdout format raw local0 info 4 | 5 | # Use only cipher suites that support FS and AEAD 6 | ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 7 | ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 8 | ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 9 | 10 | defaults 11 | log global 12 | mode tcp 13 | option tcplog 14 | option dontlognull 15 | timeout connect 15s 16 | timeout client 300s 17 | timeout server 300s 18 | 19 | # This is built-in stats page of HAProxy. You can change the hard-coded username/password in the 'stats auth' line 20 | # It will be available at http://[Bridge_Server_IP]:6543/stats or http://[Yourdomain.com]:6543/stats 21 | # It is highly recommanded to enable ssl even with a self signed certificate 22 | frontend stats 23 | mode http 24 | bind :6543 ssl crt /usr/local/etc/certificate.pem # ssl-min-ver TLSv1.1 25 | http-request redirect scheme https if !{ ssl_fc } 26 | stats enable 27 | stats hide-version 28 | stats uri /stats 29 | stats auth uzer:${HAPROXY_STATS_PASSWORD} 30 | option dontlog-normal 31 | 32 | frontend front-443 33 | bind :443 tfo 34 | tcp-request inspect-delay 10s 35 | tcp-request content accept if { req_ssl_hello_type 1 } 36 | 37 | use_backend vless-tls if { req_ssl_sni -i ${VLESS_TLS_SNI} } 38 | #use_backend nginx-tls if { req_ssl_sni -i [YOURDOMAIN.COM] } 39 | #use_backend vmess-h2 if { req_ssl_sni -i [h2.YOURDOMAIN.COM] } 40 | 41 | frontend front-80 42 | mode http 43 | bind :80 tfo 44 | option httplog 45 | #http-request redirect scheme https if { hdr_beg(Host) -i [YOURDOMAIN.COM] } !{ ssl_fc } 46 | 47 | use_backend vmess-ws if { hdr(Host) -m end -i ${VMESS_HOST} } 48 | use_backend shadowsocks-ws if { hdr(Host) -m end -i ${SHADOWSOCKS_HOST} } 49 | use_backend vless-ws if { hdr(Host) -m end -i ${VLESS_HOST} } 50 | # use_backend nginx-http if { hdr_beg(Host) -i [YOURDOMAIN.COM] } 51 | 52 | backend vmess-ws 53 | mode http 54 | balance roundrobin 55 | server upstream1 ${UPSTREAM_PUB_IP}:80 maxconn 1024 check weight 100 56 | 57 | backend shadowsocks-ws 58 | mode http 59 | server upstream1 ${UPSTREAM_PUB_IP}:100 maxconn 1024 check weight 100 60 | 61 | backend vless-ws 62 | mode http 63 | server upstream1 ${UPSTREAM_PUB_IP}:1355 maxconn 1024 check weight 100 64 | 65 | backend vless-tls 66 | mode tcp 67 | server upstream1 ${UPSTREAM_PUB_IP}:13555 maxconn 1024 check weight 100 68 | 69 | # backend nginx-http 70 | # mode http 71 | # log /dev/log local3 debug 72 | # server local 127.0.0.1:3080 maxconn 128 check 73 | 74 | # backend nginx-tls 75 | # log /dev/log local3 debug 76 | # server local 127.0.0.1:30443 maxconn 128 check 77 | 78 | # backend vmess-h2 79 | # balance roundrobin 80 | # log /dev/log local3 debug 81 | # server upstream1 ${UPSTREAM_PUB_IP}:443 maxconn 128 # check weight 100 82 | 83 | -------------------------------------------------------------------------------- /v2ray-upstream-server/config/config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "loglevel": "warning" 4 | }, 5 | "inbounds": [ 6 | { 7 | "tag": "vmess-ws", 8 | "port": 80, 9 | "protocol": "vmess", 10 | "settings": { 11 | "clients": [ 12 | { 13 | "id": "", 14 | "alterId": 0, 15 | "username": "DefaultUser" 16 | } 17 | ] 18 | }, 19 | "streamSettings": { 20 | "network": "ws", 21 | "wsSettings": { 22 | "path": "/discussion/", 23 | "headers": { 24 | "Host": "ninisite.com" 25 | } 26 | } 27 | } 28 | }, 29 | { 30 | "tag": "shadowsocks-ws", 31 | "port": 100, 32 | "protocol": "shadowsocks", 33 | "settings": { 34 | "method": "aes-128-gcm", 35 | "ota": true, 36 | "password": "" 37 | }, 38 | "streamSettings": { 39 | "network": "ws", 40 | "wsSettings": { 41 | "path": "/topics/sounds/mazhabi/", 42 | "headers": { 43 | "Host": "download.ir" 44 | } 45 | } 46 | } 47 | }, 48 | { 49 | "tag": "vless-ws", 50 | "port": 1355, 51 | "protocol": "vless", 52 | "settings": { 53 | "clients": [ 54 | { 55 | "id": "", 56 | "level": 0, 57 | "username": "DefaultUser" 58 | } 59 | ], 60 | "decryption": "none" 61 | }, 62 | "streamSettings": { 63 | "network": "ws", 64 | "wsSettings": { 65 | "connectionReuse": true, 66 | "path": "/Play/", 67 | "headers": { 68 | "Host": "sound.tebyan.net" 69 | } 70 | } 71 | } 72 | }, 73 | { 74 | "tag": "vless-tls", 75 | "port": 13555, 76 | "protocol": "vless", 77 | "settings": { 78 | "clients": [ 79 | { 80 | "id": "", 81 | "level": 0 82 | } 83 | ], 84 | "decryption": "none" 85 | }, 86 | "streamSettings": { 87 | "network": "ws", 88 | "security": "tls", 89 | "tlsSettings": { 90 | "serverName": "www.varzesh3.com", 91 | "alpn": ["h2", "http/1.1"], 92 | "certificates": [ 93 | { 94 | "certificateFile": "/etc/v2ray/certificate.crt", 95 | "keyFile": "/etc/v2ray/certificate.key" 96 | } 97 | ] 98 | } 99 | } 100 | } 101 | ], 102 | "outbounds": [ 103 | { 104 | "protocol": "freedom", 105 | "settings": {} 106 | }, 107 | { 108 | "protocol": "blackhole", 109 | "settings": {}, 110 | "tag": "block" 111 | } 112 | ], 113 | "routing": { 114 | "domainStrategy": "AsIs", 115 | "rules": [ 116 | { 117 | "type": "field", 118 | "outboundTag": "block", 119 | "protocol": [ 120 | "bittorrent" 121 | ] 122 | }, 123 | { 124 | "type": "field", 125 | "ip": [ 126 | "geoip:private" 127 | ], 128 | "outboundTag": "block" 129 | } 130 | ] 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /v2ray-upstream-server/config/config-template-with-tls.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "loglevel": "warning" 4 | }, 5 | "inbounds": [ 6 | { 7 | "tag": "vmess-ws", 8 | "port": 80, 9 | "protocol": "vmess", 10 | "settings": { 11 | "clients": [ 12 | { 13 | "id": "", 14 | "alterId": 0 15 | } 16 | ] 17 | }, 18 | "streamSettings": { 19 | "network": "ws", 20 | "wsSettings": { 21 | "path": "/discussion/", 22 | "headers": { 23 | "Host": "ninisite.com" 24 | } 25 | } 26 | } 27 | }, 28 | { 29 | "tag": "shadowsocks-ws", 30 | "port": 100, 31 | "protocol": "shadowsocks", 32 | "settings": { 33 | "method": "aes-128-gcm", 34 | "ota": true, 35 | "password": "" 36 | }, 37 | "streamSettings": { 38 | "network": "ws", 39 | "wsSettings": { 40 | "path": "/topics/sounds/mazhabi/", 41 | "headers": { 42 | "Host": "download.ir" 43 | } 44 | } 45 | } 46 | }, 47 | { 48 | "tag": "vless-ws", 49 | "port": 1355, 50 | "protocol": "vless", 51 | "settings": { 52 | "clients": [ 53 | { 54 | "id": "", 55 | "level": 0 56 | } 57 | ], 58 | "decryption": "none" 59 | }, 60 | "streamSettings": { 61 | "network": "ws", 62 | "wsSettings": { 63 | "connectionReuse": true, 64 | "path": "/Play/", 65 | "headers": { 66 | "Host": "sound.tebyan.net" 67 | } 68 | } 69 | } 70 | }, 71 | { 72 | "tag": "vmess-ws-tls", 73 | "port": 84, 74 | "protocol": "vmess", 75 | "settings": { 76 | "clients": [ 77 | { 78 | "id": "", 79 | "security": "none" 80 | } 81 | ] 82 | }, 83 | "streamSettings": { 84 | "network": "ws", 85 | "wsSettings": { 86 | "path": "/websock" 87 | } 88 | }, 89 | "security": "tls", 90 | "tlsSettings": { 91 | "certificates": [ 92 | { 93 | "certificateFile": "/etc/v2ray/domain.crt", 94 | "keyFile": "/etc/v2ray/domain.crt" 95 | } 96 | ] 97 | } 98 | }, 99 | { 100 | "tag": "vmess-tcp-tls", 101 | "port": 85, 102 | "protocol": "vmess", 103 | "settings": { 104 | "clients": [ 105 | { 106 | "id": "", 107 | "alterId": 0 108 | } 109 | ] 110 | }, 111 | "streamSettings": { 112 | "network": "tcp", 113 | "security": "tls", 114 | "tlsSettings": { 115 | "certificates": [ 116 | { 117 | "certificateFile": "/etc/v2ray/domain.crt", 118 | "keyFile": "/etc/v2ray/domain.key" 119 | } 120 | ] 121 | } 122 | } 123 | }, 124 | { 125 | "tag": "vmess-h2-tls", 126 | "port": 86, 127 | "protocol": "vmess", 128 | "settings": { 129 | "clients": [ 130 | { 131 | "id": "", 132 | "alterId": 0 133 | } 134 | ] 135 | }, 136 | "streamSettings": { 137 | "network": "h2", 138 | "httpSettings": { 139 | "path": "/bypass", 140 | "acceptProxyProtocol": true 141 | }, 142 | "security": "tls", 143 | "tlsSettings": { 144 | "certificates": [ 145 | { 146 | "serverName": "h2.varzesh3.com", 147 | "certificateFile": "/etc/v2ray/domain.crt", 148 | "keyFile": "/etc/v2ray/domain.key" 149 | } 150 | ] 151 | } 152 | } 153 | } 154 | ], 155 | "outbounds": [ 156 | { 157 | "protocol": "freedom", 158 | "settings": {} 159 | }, 160 | { 161 | "protocol": "blackhole", 162 | "settings": {}, 163 | "tag": "block" 164 | } 165 | ], 166 | "routing": { 167 | "domainStrategy": "AsIs", 168 | "rules": [ 169 | { 170 | "type": "field", 171 | "outboundTag": "block", 172 | "protocol": [ 173 | "bittorrent" 174 | ] 175 | }, 176 | { 177 | "type": "field", 178 | "ip": [ 179 | "geoip:private" 180 | ], 181 | "outboundTag": "block" 182 | } 183 | ] 184 | } 185 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # V2Ray installer for a two VPS setup 2 | 3 | **This project is a bash script that aims to setup a [V2Ray](https://www.v2fly.org/en_US/) Proxy on a Linux servers, as easily as possible!** 4 | 5 | V2fly (a community-driven edition of V2Ray) is not a proxy itself, it's a modular platform for proxies that make it possible to setup different combinations of **Proxy Protocls (like ShadowSocks, Vmess, Vless, Trojan,...)** and **Transports (like TCP, Websocket(ws), TLS, HTTP2 ...)**. Currently this combinations are the default ones: **vmess-ws, shadowsocks-ws, vless-ws and vless-ws-tls**. 6 | 7 | Note: Since these transports overlap, you might be using more than one of them at a time. For example vmess-ws-TLS uses vmess as proxy protocol, websocket as transport and wraps the whole thing in TLS for security. 8 | 9 | ## Requirements 10 | * Two VPS servers. A domestic VPS hosted in your country and a non-domestic one hosted elsewhere. 11 | 12 | * docker and docker-compose should be installed and running on those servers. Instruction to install: 13 | * **docker** 14 | * If your OS has snap installed, probably installing docker with the following command is the easiest way. 15 | ```bash 16 | sudo snap install docker 17 | ``` 18 | * If not, follow [Install Docker Engine 19 | ](https://docs.docker.com/engine/install/#server). You may take a look at [Post-installation steps for Linux](https://docs.docker.com/engine/install/linux-postinstall/) to add your user to docker group as well. 20 | 21 | * **docker-compose** Download the binary (compatible with the installed docker engine in previous step) [Install Docker Compose](https://docs.docker.com/compose/install/) 22 | 23 | *NOTE: If installed docker via snap, docker-compose is also installed with it. 24 | 25 | ## Terminology 26 | 27 | * Upstream Server: A server that has free access to the Internet. 28 | * Bridge Server: A server that is available to clients and has access to the upstream server. HAProxy runs here. This server acts only as a layer4 TCP or layer7 HTTP relay(i.e recieves client request => forwards request to Upstream server => recieve response from upstream => forwards response to client ) 29 | * Client: A user-side application with access to the bridge server. 30 | 31 | ``` 32 | (Client) <-> [ Bridge Server (HAProxy) ] <-> [ Upstream Server (V2Ray) ] <-> (Internet) 33 | ``` 34 | 35 | ## Usage 36 | ### Server 37 | Clone the repo and execute the insall script on both bridge and upstream server. Answer the questions asked by the script and it will take care of the rest. 38 | 39 | ```bash 40 | git clone https://github.com/UZziell/v2ray-haproxy-docker; 41 | cd v2ray-haproxy-docker; 42 | chmod +x v2ray-install.sh; 43 | sudo ./v2ray-install.sh 44 | ``` 45 | Run the script again to uninstall the service. 46 | When the setup is over on the *Upstream* server, 3 QRCodes and URLs **(vmess://, vless://, ss://)** will be generated for clients. After added configs in the client app: 47 | * Those that end in **Bridged** should work all the time (i.e during internet shutdown) 48 | * Those configs that end with **Direct**, connect directly to the upstream server (the speed is better but only works in "normal" times). 49 | 50 | 51 | ### Client 52 | Install the appropriate app from the list below and add the server by scanning the QRCode or using the link. 53 | 54 | #### VMess and Vless Protocol 55 | In theory any v2ray client should work. 56 | 57 | Tested clients apps: 58 | * **Android**: [XRAY VPN](https://play.google.com/store/apps/details?id=vpn.v2ray.xray&hl=en&gl=US) - [v2rayNG](https://play.google.com/store/apps/details?id=com.v2ray.ang&hl=en&gl=US) 59 | 60 | * **IOS**: [Fair](https://apps.apple.com/us/app/fair-vpn/id1533873488) - [ShadowLink](https://apps.apple.com/us/app/shadowlink-shadowsocks-vpn/id1439686518) 61 | 62 | * **Linux**: 63 | * CLI: v2ray package - [v2fly](https://github.com/v2fly/fhs-install-v2ray) 64 | * GUI: [nekoray](https://github.com/MatsuriDayo/nekoray/releases) 65 | 66 | * **MacOs**: [V2rayU](https://github.com/yanue/V2rayU/tree/master) 67 | 68 | * **Windows**: [nekoray](https://github.com/MatsuriDayo/nekoray/releases) 69 | 70 | 71 | 72 | #### Shadowsocks Protocol 73 | 74 | These are recommended client apps: 75 | * **Android**: [Shadowsocks](https://play.google.com/store/apps/details?id=com.github.shadowsocks&hl=en&gl=US) + [V2ray Plugin](https://play.google.com/store/apps/details?id=com.github.shadowsocks.plugin.v2ray&hl=en&gl=US) 76 | 77 | 78 | 79 | ## P.S. 80 | 81 | This repository is kind of forked from [v2ray-docker-compose 82 | ](https://github.com/miladrahimi/v2ray-docker-compose). 83 | Regards to [@miladrahimi](https://github.com/miladrahimi) and other contributors. 84 | 85 |

(back to top)

86 | 87 | -------------------------------------------------------------------------------- /v2ray-docker-client/config/config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "loglevel": "warning" 4 | }, 5 | "inbounds": [ 6 | { 7 | "tag": "1081", 8 | "port": 1081, 9 | "listen": "127.0.0.1", 10 | "protocol": "socks", 11 | "settings": { 12 | "udp": false 13 | } 14 | }, 15 | { 16 | "tag": "1082", 17 | "port": 1082, 18 | "listen": "127.0.0.1", 19 | "protocol": "socks", 20 | "settings": { 21 | "udp": false 22 | } 23 | }, 24 | { 25 | "tag": "1083", 26 | "port": 1083, 27 | "listen": "127.0.0.1", 28 | "protocol": "socks", 29 | "settings": { 30 | "udp": false 31 | } 32 | }, 33 | { 34 | "tag": "http", 35 | "port": 8118, 36 | "protocol": "http", 37 | "settings": {} 38 | } 39 | ], 40 | "outbounds": [ 41 | { 42 | "tag": "vmess-ws", 43 | "protocol": "vmess", 44 | "settings": { 45 | "vnext": [ 46 | { 47 | "address": "", 48 | "port": 80, 49 | "users": [ 50 | { 51 | "id": "", 52 | "alterId": 0 53 | } 54 | ] 55 | } 56 | ] 57 | }, 58 | "streamSettings": { 59 | "network": "ws", 60 | "wsSettings": { 61 | "connectionReuse": true, 62 | "path": "/discussion/", 63 | "headers": { 64 | "Host": "ninisite.com" 65 | } 66 | } 67 | }, 68 | "mux": { 69 | "enabled": true 70 | } 71 | }, 72 | { 73 | "tag": "shadowsocks-ws", 74 | "protocol": "shadowsocks", 75 | "settings": { 76 | "servers": [ 77 | { 78 | "address": "", 79 | "port": 80, 80 | "method": "aes-128-gcm", 81 | "password": "" 82 | } 83 | ] 84 | }, 85 | "streamSettings": { 86 | "network": "ws", 87 | "wsSettings": { 88 | "connectionReuse": true, 89 | "path": "/topics/sounds/mazhabi/", 90 | "headers": { 91 | "Host": "download.ir" 92 | } 93 | } 94 | }, 95 | "mux": { 96 | "enabled": true 97 | } 98 | }, 99 | { 100 | "tag": "vless-ws", 101 | "protocol": "vless", 102 | "settings": { 103 | "vnext": [ 104 | { 105 | "address": "", 106 | "port": 1355, 107 | "users": [ 108 | { 109 | "id": "", 110 | "encryption": "none", 111 | "level": 0 112 | } 113 | ] 114 | } 115 | ] 116 | }, 117 | "streamSettings": { 118 | "network": "ws", 119 | "wsSettings": { 120 | "connectionReuse": true, 121 | "path": "/Play/", 122 | "headers": { 123 | "Host": "sound.tebyan.net" 124 | } 125 | } 126 | }, 127 | "mux": { 128 | "enabled": true 129 | } 130 | }, 131 | { 132 | "tag": "vless-tls", 133 | "protocol": "vless", 134 | "settings": { 135 | "vnext": [ 136 | { 137 | "address": "", 138 | "port": 443, 139 | "users": [ 140 | { 141 | "id": "", 142 | "level": 0, 143 | "encryption": "none" 144 | } 145 | ] 146 | } 147 | ] 148 | }, 149 | "streamSettings": { 150 | "network": "ws", 151 | "security": "tls", 152 | "tlsSettings": { 153 | "serverName": "www.varzesh3.com", 154 | "allowInsecure": true 155 | } 156 | }, 157 | "mux": { 158 | "enabled": true 159 | } 160 | }, 161 | { 162 | "protocol": "freedom", 163 | "settings": {}, 164 | "tag": "direct" 165 | } 166 | ], 167 | "routing": { 168 | "strategy": "rules", 169 | "settings": { 170 | "rules": [ 171 | { 172 | "type": "field", 173 | "outboundTag": "vmess-ws", 174 | "inboundTag": [ 175 | "1081" 176 | ] 177 | }, 178 | { 179 | "type": "field", 180 | "outboundTag": "shadowsocks-ws", 181 | "inboundTag": [ 182 | "1082" 183 | ] 184 | }, 185 | { 186 | "type": "field", 187 | "outboundTag": "vless-ws", 188 | "inboundTag": [ 189 | "1083" 190 | ] 191 | }, 192 | { 193 | "type": "field", 194 | "outboundTag": "vmess-ws", 195 | "inboundTag": [ 196 | "http" 197 | ] 198 | }, 199 | { 200 | "type": "field", 201 | "outboundTag": "direct", 202 | "domain": [ 203 | "regexp:.*\\.ir$" 204 | ] 205 | }, 206 | { 207 | "type": "field", 208 | "outboundTag": "direct", 209 | "ip": [ 210 | "geoip:private", 211 | "geoip:ir" 212 | ] 213 | }, 214 | { 215 | "type": "field", 216 | "outboundTag": "direct", 217 | "protocol": [ 218 | "bittorrent" 219 | ] 220 | } 221 | ] 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /v2ray-docker-client/config/config-template-with-tls.json: -------------------------------------------------------------------------------- 1 | { 2 | "log": { 3 | "loglevel": "warning" 4 | }, 5 | "inbounds": [ 6 | { 7 | "tag": "1081", 8 | "port": 1081, 9 | "listen": "127.0.0.1", 10 | "protocol": "socks", 11 | "settings": { 12 | "udp": false 13 | } 14 | }, 15 | { 16 | "tag": "1082", 17 | "port": 1082, 18 | "listen": "127.0.0.1", 19 | "protocol": "socks", 20 | "settings": { 21 | "udp": false 22 | } 23 | }, 24 | { 25 | "tag": "1083", 26 | "port": 1083, 27 | "listen": "127.0.0.1", 28 | "protocol": "socks", 29 | "settings": { 30 | "udp": false 31 | } 32 | }, 33 | { 34 | "tag": "1084", 35 | "port": 1084, 36 | "listen": "127.0.0.1", 37 | "protocol": "socks", 38 | "settings": { 39 | "udp": false 40 | } 41 | }, 42 | { 43 | "tag": "1085", 44 | "port": 1085, 45 | "listen": "127.0.0.1", 46 | "protocol": "socks", 47 | "settings": { 48 | "udp": false 49 | } 50 | }, 51 | { 52 | "tag": "1086", 53 | "port": 1086, 54 | "listen": "127.0.0.1", 55 | "protocol": "socks", 56 | "settings": { 57 | "udp": false 58 | } 59 | }, 60 | { 61 | "tag": "http", 62 | "port": 8118, 63 | "protocol": "http", 64 | "settings": {} 65 | } 66 | ], 67 | "outbounds": [ 68 | { 69 | "tag": "vmess-ws", 70 | "protocol": "vmess", 71 | "settings": { 72 | "vnext": [ 73 | { 74 | "address": "", 75 | "port": 80, 76 | "users": [ 77 | { 78 | "id": "", 79 | "alterId": 0 80 | } 81 | ] 82 | } 83 | ] 84 | }, 85 | "streamSettings": { 86 | "network": "ws", 87 | "wsSettings": { 88 | "connectionReuse": true, 89 | "path": "/discussion/", 90 | "headers": { 91 | "Host": "ninisite.com" 92 | } 93 | } 94 | }, 95 | "mux": { 96 | "enabled": true 97 | } 98 | }, 99 | { 100 | "tag": "shadowsocks-ws", 101 | "protocol": "shadowsocks", 102 | "settings": { 103 | "servers": [ 104 | { 105 | "address": "", 106 | "port": 100, 107 | "method": "aes-128-gcm", 108 | "password": "" 109 | } 110 | ] 111 | }, 112 | "streamSettings": { 113 | "network": "ws", 114 | "wsSettings": { 115 | "connectionReuse": true, 116 | "path": "/topics/sounds/mazhabi/", 117 | "headers": { 118 | "Host": "download.ir" 119 | } 120 | } 121 | }, 122 | "mux": { 123 | "enabled": true 124 | } 125 | }, 126 | { 127 | "tag": "vless-ws", 128 | "protocol": "vless", 129 | "settings": { 130 | "vnext": [ 131 | { 132 | "address": "", 133 | "port": 1355, 134 | "users": [ 135 | { 136 | "id": "", 137 | "encryption": "none", 138 | "level": 0 139 | } 140 | ] 141 | } 142 | ] 143 | }, 144 | "streamSettings": { 145 | "network": "ws", 146 | "wsSettings": { 147 | "connectionReuse": true, 148 | "path": "/Play/", 149 | "headers": { 150 | "Host": "sound.tebyan.net" 151 | } 152 | } 153 | }, 154 | "mux": { 155 | "enabled": true 156 | } 157 | }, 158 | { 159 | "tag": "vmess-ws-tls", 160 | "protocol": "vmess", 161 | "settings": { 162 | "vnext": [ 163 | { 164 | "address": "", 165 | "port": 84, 166 | "users": [ 167 | { 168 | "id": "", 169 | "security": "none" 170 | } 171 | ] 172 | } 173 | ] 174 | }, 175 | "streamSettings": { 176 | "network": "ws", 177 | "wsSettings": { 178 | "path": "/websock" 179 | }, 180 | "security": "tls" 181 | }, 182 | "mux": { 183 | "enabled": true 184 | } 185 | }, 186 | { 187 | "tag": "vmess-tcp-tls", 188 | "protocol": "vmess", 189 | "settings": { 190 | "vnext": [ 191 | { 192 | "address": "", 193 | "port": 85, 194 | "users": [ 195 | { 196 | "id": "", 197 | "alterId": 0, 198 | "security": "none" 199 | } 200 | ] 201 | } 202 | ] 203 | }, 204 | "streamSettings": { 205 | "network": "tcp", 206 | "security": "tls" 207 | }, 208 | "mux": { 209 | "enabled": true 210 | } 211 | }, 212 | { 213 | "tag": "vmess-h2-tls", 214 | "protocol": "vmess", 215 | "settings": { 216 | "vnext": [ 217 | { 218 | "address": "", 219 | "port": 86, 220 | "users": [ 221 | { 222 | "id": "", 223 | "alterId": 0 224 | } 225 | ] 226 | } 227 | ] 228 | }, 229 | "streamSettings": { 230 | "network": "h2", 231 | "httpSettings": { 232 | "path": "/bypass" 233 | }, 234 | "security": "tls", 235 | "tlsSettings": { 236 | "serverName": "h2.varzesh3.com" 237 | } 238 | }, 239 | "mux": { 240 | "enabled": true 241 | } 242 | }, 243 | { 244 | "protocol": "freedom", 245 | "settings": {}, 246 | "tag": "direct" 247 | } 248 | ], 249 | "routing": { 250 | "strategy": "rules", 251 | "settings": { 252 | "rules": [ 253 | { 254 | "type": "field", 255 | "outboundTag": "vmess-ws", 256 | "inboundTag": [ 257 | "1081" 258 | ] 259 | }, 260 | { 261 | "type": "field", 262 | "outboundTag": "vmess-ws-tls", 263 | "inboundTag": [ 264 | "1082" 265 | ] 266 | }, 267 | { 268 | "type": "field", 269 | "outboundTag": "wmess-tcp-tls", 270 | "inboundTag": [ 271 | "1083" 272 | ] 273 | }, 274 | { 275 | "type": "field", 276 | "outboundTag": "vmess-h2-tls", 277 | "inboundTag": [ 278 | "1084" 279 | ] 280 | }, 281 | { 282 | "type": "field", 283 | "outboundTag": "shadowsocks-ws", 284 | "inboundTag": [ 285 | "1085" 286 | ] 287 | }, 288 | { 289 | "type": "field", 290 | "outboundTag": "vless-ws", 291 | "inboundTag": [ 292 | "http" 293 | ] 294 | }, 295 | { 296 | "type": "field", 297 | "outboundTag": "direct", 298 | "domain": [ 299 | "regexp:.*\\.ir$" 300 | ] 301 | }, 302 | { 303 | "type": "field", 304 | "outboundTag": "direct", 305 | "ip": [ 306 | "geoip:private", 307 | "geoip:ir" 308 | ] 309 | }, 310 | { 311 | "type": "field", 312 | "outboundTag": "direct", 313 | "protocol": [ 314 | "bittorrent" 315 | ] 316 | } 317 | ] 318 | } 319 | } 320 | } -------------------------------------------------------------------------------- /v2ray-install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # v2ray installer 4 | # https://github.com/UZziell/v2ray-haproxy-docker 5 | # with regards to: 6 | # https://github.com/angristan/wireguard-install 7 | # https://github.com/miladrahimi/v2ray-docker-compose 8 | 9 | DATA_DIR="$PWD/v2ray-data" 10 | 11 | COLOR_PREFIX="\033[" 12 | # color code 13 | RED="31" # error 14 | GREEN="32" # success 15 | YELLOW="33" # warning 16 | BLUE="34" # info 17 | CYAN="36" # instruction 18 | NORMAL="0" # reset 19 | 20 | colorEcho(){ 21 | echo -e "${COLOR_PREFIX}${1}m${@:2}${COLOR_PREFIX}${NORMAL}m" 22 | } 23 | 24 | function isRoot() { 25 | if [ "${EUID}" -ne 0 ]; then 26 | echo "You need to run this script as root" 27 | exit 1 28 | fi 29 | } 30 | 31 | function checkDocker() { 32 | if ! [[ $(which docker) && $(docker ps) ]]; then 33 | colorEcho ${RED} "docker is not installed/running" 34 | exit 1 35 | elif ! [[ $(which docker-compose) ]]; then 36 | colorEcho ${RED} "docker-compose is not installed" 37 | exit 1 38 | fi 39 | 40 | } 41 | 42 | function checkOS() { 43 | # Check OS version 44 | if [[ -e /etc/debian_version ]]; then 45 | source /etc/os-release 46 | OS="${ID}" # debian or ubuntu 47 | if [[ ${ID} == "debian" || ${ID} == "raspbian" ]]; then 48 | if [[ ${VERSION_ID} -lt 10 ]]; then 49 | colorEcho ${RED} "Your version of Debian (${VERSION_ID}) is not supported. Please use Debian 10 Buster or later" 50 | exit 1 51 | fi 52 | OS=debian # overwrite if raspbian 53 | fi 54 | elif [[ -e /etc/fedora-release ]]; then 55 | source /etc/os-release 56 | OS="${ID}" 57 | elif [[ -e /etc/arch-release ]]; then 58 | OS=arch 59 | else 60 | colorEcho ${RED} "Looks like you aren't running this installer on a Debian, Ubuntu, Fedora, CentOS, Oracle or Arch Linux system" 61 | exit 1 62 | fi 63 | } 64 | 65 | function initialCheck() { 66 | isRoot 67 | checkDocker 68 | checkOS 69 | } 70 | 71 | function installQuestions() { 72 | colorEcho ${CYAN} "Welcome to the V2Ray installer!" 73 | echo "The git repository is available at: https://github.com/UZziell/v2ray-haproxy-docker" 74 | echo "" 75 | echo "I need to ask you a few questions before starting the setup." 76 | echo "You can use the default values if they are correct and just press Enter" 77 | echo "Ready to use QRCode and URLs for Vmess, Shadowsocks and Vless will be auto-generated after setup is finished" 78 | echo "" 79 | 80 | # detect server type (bridge or upstream) 81 | until [[ ${SERVER_TYPE} =~ ^(bridge|upstream)$ ]]; do 82 | read -rp "Which server is this?(bridge or upstream) " -e -i "upstream" SERVER_TYPE 83 | done 84 | 85 | # Detect public IPv4 or IPv6 address and pre-fill for the user 86 | SERVER_PUB_IP=$(ip -4 addr | sed -ne 's|^.* inet \([^/]*\)/.* scope global.*$|\1|p' | awk '{print $1}' | head -1) 87 | if [[ -z ${SERVER_PUB_IP} ]]; then 88 | # Detect public IPv6 address 89 | SERVER_PUB_IP=$(ip -6 addr | sed -ne 's|^.* inet6 \([^/]*\)/.* scope global.*$|\1|p' | head -1) 90 | fi 91 | read -rp "Public IPv4 public address(current server): " -e -i "${SERVER_PUB_IP}" SERVER_PUB_IP 92 | 93 | # # Use TLS? 94 | # until [[ ${USE_TLS} =~ ^(y|n)$ ]]; do 95 | # read -rp "Do you have want to enable TLS? You should have a domain and a valid certificate. (y/n) " -e -i "n" USE_TLS 96 | # done 97 | 98 | # if [[ $USE_TLS == "y" ]]; then 99 | # until [[ -f ${CERT_PATH} ]]; do 100 | # read -rp "Enter the path to your CERTIFICATE file: " -e -i "$PWD/" CERT_PATH 101 | # done 102 | # until [[ -f ${KEY_PATH} ]]; do 103 | # read -rp "Enter the path to your KEY file: " -e -i "$PWD/" KEY_PATH 104 | # done 105 | 106 | # CERT_SHA=$(openssl x509 -in $CERT_PATH -pubkey -noout -outform pem | sha256sum) 107 | # KEY_SHA=$(openssl pkey -in $KEY_PATH -pubout -outform pem | sha256sum) 108 | # if [[ $CERT_SHA != $KEY_SHA ]]; then 109 | # colorEcho ${RED} "Certificate/Key pair does not seem to match" 110 | # exit 1 111 | # fi 112 | # fi 113 | 114 | if [[ $SERVER_TYPE == "bridge" ]]; then 115 | if [[ $USE_TLS == "y" ]]; then 116 | colorEcho ${YELLOW} "NOTE: You should create an A or AAAA(in case of IPv6) record for your domain that point to $SERVER_PUB_IP" 117 | fi 118 | 119 | # Upstream public IP 120 | until [[ ${UPSTREAM_PUB_IP} =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; do 121 | read -rp "Upstream server public IPv4: " UPSTREAM_PUB_IP 122 | done 123 | 124 | 125 | elif [[ $SERVER_TYPE == "upstream" ]]; then 126 | # Bridge public IP (to generate config files) 127 | until [[ ${BRIDGE_PUB_ADDRESS} =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || [[ ${BRIDGE_PUB_ADDRESS} =~ ^([A-Za-z0-9-]{1,63}\.)+[A-Za-z]{2,6}$ ]]; do 128 | read -rp "Bridge server's public IPv4 or Domain name: " BRIDGE_PUB_ADDRESS 129 | done 130 | 131 | fi 132 | 133 | # # Generate random number within private ports range 134 | # RANDOM_PORT=$(shuf -i49152-65535 -n1) 135 | # until [[ ${CLIENT_DNS_2} =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; do 136 | 137 | echo "" 138 | colorEcho ${GREEN} "That's all. Setting up $SERVER_TYPE server now!" 139 | # read -n1 -r -p "Press any key to continue..."; echo 140 | } 141 | 142 | function installPackages(){ 143 | colorEcho ${GREEN} "Installing needed packages: $1" 144 | if [[ ${OS} == 'ubuntu' ]] || [[ ${OS} == 'debian' && ${VERSION_ID} -gt 10 ]]; then 145 | apt-get update 146 | apt-get install -y $1 147 | elif [[ ${OS} == 'fedora' ]]; then 148 | dnf install -y $1 149 | elif [[ ${OS} == 'centos' ]]; then 150 | yum -y install epel-release elrepo-release 151 | if [[ ${VERSION_ID} -eq 7 ]]; then 152 | yum -y install yum-plugin-elrepo 153 | fi 154 | yum -y install $1 155 | elif [[ ${OS} == 'arch' ]]; then 156 | pacman -S --needed --noconfirm $1 157 | fi 158 | } 159 | 160 | 161 | function pullDockerImage() { 162 | IMAGE_FILE="/tmp/image.tar" 163 | if [[ $1 == "v2ray" ]]; then 164 | IMAGE_ID='0e75a60ce4c9' 165 | IMAGE_TAR_SHA1SUM='c088e58adf57e10c0631831f1c5676296a169b94' 166 | PROJECT_DIR='v2ray-upstream-server' 167 | IMAGE_DOWNLOAD_LINK='https://github.com/UZziell/v2ray-haproxy-docker/releases/download/docker-images/v2fly-v2flycore-v5.1.0-0e75a60ce4c9.tar' 168 | elif [[ $1 == "haproxy" ]]; then 169 | IMAGE_ID='6e2d5dace12f' 170 | IMAGE_TAR_SHA1SUM='6f5422b2d9b97728dfb4091b79d8d4baff0217b6' 171 | PROJECT_DIR='haproxy-bridge-server' 172 | IMAGE_DOWNLOAD_LINK='https://github.com/UZziell/v2ray-haproxy-docker/releases/download/docker-images/haproxy-lts-bullseye-6e2d5dace12f.tar' 173 | fi 174 | 175 | colorEcho ${GREEN} "Pulling $1 image." 176 | 177 | docker images | grep $IMAGE_ID || docker-compose --project-directory $PROJECT_DIR pull 178 | if [[ $? -ne 0 ]]; then 179 | [[ -e $IMAGE_FILE ]] || env all_proxy=$all_proxy curl -fSLo $IMAGE_FILE $IMAGE_DOWNLOAD_LINK 180 | if [[ $(sha1sum $IMAGE_FILE | awk '{print $1}') == $IMAGE_TAR_SHA1SUM ]]; then 181 | cat $IMAGE_FILE | docker load 182 | else 183 | colorEcho ${RED} "Could not pull '$1' image from dockerhub or even github releases)" 184 | colorEcho ${YELLOW} "If it keeps failing, your server cannot access github.com right now. You can try manually donwling '$IMAGE_DOWNLOAD_LINK' and use 'scp' to copy it to the server,\ 185 | then use 'docker image load -i v2fly-v2flycore-v5.1.0-0e75a60ce4c9.tar' OR try some other time" 186 | rm $IMAGE_FILE 187 | exit 1 188 | fi 189 | fi 190 | } 191 | 192 | function generateQR() { 193 | colorEcho ${BLUE} "########## $1 client configs(URL & QRCode) ##########" 194 | echo -n $2 | qrencode -t ansiutf8 | tee -a $DATA_DIR/v2ray-defaultUser 195 | echo -e "$2\n\n" | tee -a $DATA_DIR/v2ray-defaultUser 196 | sleep 2 197 | } 198 | 199 | function parseConfig() { 200 | TAG=$1 201 | PROTOCOL=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .protocol)" $V2RAY_SERVER_CONFIG) 202 | if [[ $PROTOCOL =~ ^(vmess|vless)$ ]]; then 203 | PORT=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .port)" $V2RAY_SERVER_CONFIG) 204 | WS_HOST=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .streamSettings.wsSettings.headers.Host)" $V2RAY_SERVER_CONFIG) 205 | WS_PATH=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .streamSettings.wsSettings.path)" $V2RAY_SERVER_CONFIG) 206 | TLS_SNI=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .streamSettings.tlsSettings.serverName)" $V2RAY_SERVER_CONFIG) 207 | 208 | if [[ $PROTOCOL == 'vmess' ]]; then 209 | VMESS_URL=$(echo -n "vmess://$(echo -n "{'add': '$BRIDGE_PUB_ADDRESS', 'aid': '0', 'host': '$WS_HOST', 'id': '$UUID', \ 210 | 'net': 'ws', 'path': '$WS_PATH', 'port': '80', 'ps': 'VMESS-Bridged', 'tls': '', 'type': 'none', 'v': '2'}" | base64 -w 0)") 211 | VMESS_URL_DIRECT=$(echo -n "vmess://$(echo -n "{'add': '$SERVER_PUB_IP', 'aid': '0', 'host': '$WS_HOST', 'id': '$UUID', \ 212 | 'net': 'ws', 'path': '$WS_PATH', 'port': '$PORT', 'ps': 'VMESS-Direct', 'tls': '', 'type': 'none', 'v': '2'}" | base64 -w 0)") 213 | 214 | if [[ $TLS_SNI != 'null' ]]; then 215 | VMESS_URL=$(echo -n "vmess://$(echo -n "{'add': '$BRIDGE_PUB_ADDRESS', 'aid': '0', 'host': '$WS_HOST', 'id': '$UUID', \ 216 | 'net': 'ws', 'path': '$WS_PATH', 'port': '443', 'ps': 'VMESS-Bridged', 'tls': 'tls', 'type': 'none', 'v': '2'}" | base64 -w 0)") 217 | VMESS_URL_DIRECT=$(echo -n "vmess://$(echo -n "{'add': '$SERVER_PUB_IP', 'aid': '0', 'host': '$WS_HOST', 'id': '$UUID', \ 218 | 'net': 'ws', 'path': '$WS_PATH', 'port': '$PORT', 'ps': 'VMESS-Direct', 'tls': 'tls', 'type': 'none', 'v': '2'}" | base64 -w 0)") 219 | fi 220 | generateQR "vmess" $VMESS_URL 221 | generateQR "vmess" $VMESS_URL_DIRECT 222 | 223 | elif [[ $PROTOCOL == 'vless' ]]; then 224 | VLESS_URL=$(echo -n "vless://${UUID}@${BRIDGE_PUB_ADDRESS}:80?type=ws&path=${WS_PATH}&host=${WS_HOST}#VLESS-Bridged") 225 | VLESS_URL_DIRECT=$(echo -n "vless://${UUID}@${SERVER_PUB_IP}:${PORT}?type=ws&path=${WS_PATH}&host=${WS_HOST}#VLESS-Direct") 226 | 227 | if [[ $TLS_SNI != 'null' ]]; then 228 | VLESS_URL=$(echo -n "vless://${UUID}@${BRIDGE_PUB_ADDRESS}:443?type=ws&security=tls&encryption=none&host=${TLS_SNI}&sni=${TLS_SNI}#VLESS-TLS-Bridged") 229 | VLESS_URL_DIRECT=$(echo -n "vless://${UUID}@${SERVER_PUB_IP}:${PORT}?type=ws&security=tls&encryption=none&host=${TLS_SNI}&sni=${TLS_SNI}#VLESS-TLS-Direct") 230 | fi 231 | generateQR "vless" $VLESS_URL 232 | generateQR "vless" $VLESS_URL_DIRECT 233 | fi 234 | 235 | elif [[ $PROTOCOL == 'shadowsocks' ]]; then 236 | # SHADOWSOCKS READ MORE ABOUT SS URI SCHEME at https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme 237 | SHADOWSOCKS_HOST=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .streamSettings.wsSettings.headers.Host)" $V2RAY_SERVER_CONFIG) 238 | SHADOWSOCKS_PATH=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .streamSettings.wsSettings.path)" $V2RAY_SERVER_CONFIG) 239 | SHADOWSOCKS_METHOD=$(jq -r "(.inbounds[] | select(.tag | match(\"^($TAG)$\")) | .settings.method)" $V2RAY_SERVER_CONFIG) 240 | SHADOWSOCKS_URL=$(echo -n "ss://$(echo -n ${SHADOWSOCKS_METHOD}:${SHADOWSOCKS_PASSWORD} | base64 -w0)@${BRIDGE_PUB_ADDRESS}:80/?plugin=v2ray-plugin;mux=0;mode=websocket;host=${SHADOWSOCKS_HOST};path=${SHADOWSOCKS_PATH}#Shadowsocks") 241 | generateQR "shadowsocks" $SHADOWSOCKS_URL 242 | 243 | fi 244 | 245 | } 246 | 247 | function installConfigRun() { 248 | mkdir -p $DATA_DIR 249 | V2RAY_CLIENT_CONFIG="./v2ray-docker-client/config/config.json" 250 | V2RAY_CLIENT_CONFIG_TEMPLATE="./v2ray-docker-client/config/config-template.json" 251 | V2RAY_SERVER_CONFIG="./v2ray-upstream-server/config/config.json" 252 | V2RAY_SERVER_CONFIG_TEMPLATE="./v2ray-upstream-server/config/config-template.json" 253 | V2RAY_SERVER_CERTIFICATE="./v2ray-upstream-server/config/certificate.crt" 254 | V2RAY_SERVER_CERTIFICATE_KEY="./v2ray-upstream-server/config/certificate.key" 255 | HAPROXY_CONFIG="./haproxy-bridge-server/haproxy.cfg" 256 | HAPROXY_CONFIG_TEMPLATE="./haproxy-bridge-server/haproxy-template.cfg" 257 | HAPROXY_CERTIFICATE="./haproxy-bridge-server/certificate.pem" 258 | 259 | # Run setup questions first 260 | installQuestions 261 | 262 | 263 | if [[ $SERVER_TYPE == "upstream" ]]; then 264 | # Install needed tools (jq, moreutils, qrencode) and pull docker image 265 | installPackages "jq moreutils qrencode" 266 | pullDockerImage "v2ray" 267 | 268 | # TLS 269 | if [[ $USE_TLS == "y" ]]; then 270 | cp $CERT_PATH $V2RAY_SERVER_CERTIFICATE 271 | cp $KEY_PATH $V2RAY_SERVER_CERTIFICATE_KEY 272 | else 273 | echo "Generating a self-signed certificate for proxy protocols that use TLS as security" 274 | openssl req -x509 -newkey rsa:2048 -keyout $V2RAY_SERVER_CERTIFICATE_KEY -out $V2RAY_SERVER_CERTIFICATE -sha256 -nodes -days 365 -subj "/CN=$SERVER_PUB_IP" 2> /dev/null 275 | fi 276 | # prepare V2Ray config files 277 | export UUID=$(cat /proc/sys/kernel/random/uuid) 278 | export SHADOWSOCKS_PASSWORD=$(openssl rand -hex 10) 279 | # Server 280 | # Set vmess/vless UUIDs and shadowsocks password 281 | jq "(.inbounds[] | select(.protocol | match(\"^(vmess|vless)$\")) | .settings.clients[].id) |= \"$UUID\" | \ 282 | (.inbounds[] | select(.protocol | match(\"^(vmess|vless)$\")) | .settings.clients[].username) |= \"DefaultUser\" | \ 283 | (.inbounds[] | select(.protocol | match(\"^(shadowsocks)$\")) | .settings.password) |= \"$SHADOWSOCKS_PASSWORD\" " $V2RAY_SERVER_CONFIG_TEMPLATE > ${V2RAY_SERVER_CONFIG} 284 | # Client 285 | # Set vmess/vless UUIDs, shadowsocks password, and bridge address 286 | jq "(.outbounds[] | select(.protocol | match(\"^(vmess|vless)$\")) | .settings.vnext[].users[].id) |= \"$UUID\" | \ 287 | (.outbounds[] | select(.protocol | match(\"^(vmess|vless)$\")) | .settings.vnext[].address) |= \"$BRIDGE_PUB_ADDRESS\" | \ 288 | (.outbounds[] | select(.protocol | match(\"^shadowsocks$\")) | .settings.servers[].address) |= \"$BRIDGE_PUB_ADDRESS\" | \ 289 | (.outbounds[] | select(.protocol | match(\"^shadowsocks$\")) | .settings.servers[].password) |= \"$SHADOWSOCKS_PASSWORD\" " $V2RAY_CLIENT_CONFIG_TEMPLATE > ${V2RAY_CLIENT_CONFIG} 290 | 291 | # Run V2Ray 292 | docker-compose --project-directory v2ray-upstream-server up -d 293 | # check if running 294 | sleep 5 && checkContainerRunning "v2ray_upstream" 295 | 296 | colorEcho ${GREEN} "$SERVER_TYPE server setup finished successfully" 297 | printf "\n\n" 298 | read -n1 -r -p "Press any key to show client configs..."; echo 299 | 300 | # Parse server config and generate client QRCode/URL 301 | for inbound in $(jq -r '(.inbounds[] | .tag )' $V2RAY_SERVER_CONFIG_TEMPLATE); do 302 | parseConfig $inbound 303 | done 304 | colorEcho ${YELLOW} "Saved DefaultUser's configs to '$DATA_DIR/v2ray-defaultUser' for later use\n" 305 | 306 | 307 | elif [[ $SERVER_TYPE == "bridge" ]]; then 308 | installPackages "jq" 309 | pullDockerImage "haproxy" 310 | 311 | # Prepare HAProxy config 312 | VMESS_HOST=$(jq -r '(.inbounds[] | select(.tag | match("^(vmess-ws)$")) | .streamSettings.wsSettings.headers.Host)' $V2RAY_SERVER_CONFIG_TEMPLATE) 313 | SHADOWSOCKS_HOST=$(jq -r '(.inbounds[] | select(.protocol | match("^(shadowsocks)$")) | .streamSettings.wsSettings.headers.Host)' $V2RAY_SERVER_CONFIG_TEMPLATE) 314 | VLESS_HOST=$(jq -r '(.inbounds[] | select(.tag | match("^(vless-ws)$")) | .streamSettings.wsSettings.headers.Host)' $V2RAY_SERVER_CONFIG_TEMPLATE) 315 | VLESS_TLS_SNI=$(jq -r '(.inbounds[] | select(.tag | match("^(vless-tls)$")) | .streamSettings.tlsSettings.serverName)' $V2RAY_SERVER_CONFIG_TEMPLATE) 316 | export HAPROXY_STATS_PASSWORD=$(openssl rand -hex 20) UPSTREAM_PUB_IP VMESS_HOST SHADOWSOCKS_HOST VLESS_HOST VLESS_TLS_SNI 317 | envsubst '$HAPROXY_STATS_PASSWORD $UPSTREAM_PUB_IP $VMESS_HOST $SHADOWSOCKS_HOST $VLESS_HOST $VLESS_TLS_SNI' < $HAPROXY_CONFIG_TEMPLATE > $HAPROXY_CONFIG 318 | 319 | # Use entered certificate or generate a self-sign cert for HAProxy 320 | if [[ $USE_TLS == "y" ]]; then 321 | cat $CERT_PATH $KEY_PATH > $HAPROXY_CERTIFICATE 322 | else 323 | echo "Generating a self-signed certificate for HAProxy stats page" 324 | openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -sha256 -nodes -days 365 -subj "/CN=$SERVER_PUB_IP" 2> /dev/null 325 | cat cert.pem key.pem > $HAPROXY_CERTIFICATE && rm -f key.pem cert.pem 326 | fi 327 | 328 | # Run HAProxy 329 | docker-compose --project-directory haproxy-bridge-server up -d 330 | sleep 5 && checkContainerRunning "haproxy_bridge" 331 | colorEcho ${GREEN} "$SERVER_TYPE server setup finished." 332 | colorEcho ${GREEN} "HAProxy stats page url: https://${SERVER_PUB_IP}:6543/stats" 333 | colorEcho ${GREEN} "username: uzer\npassword: $HAPROXY_STATS_PASSWORD" 334 | colorEcho ${YELLOW} "Save this credentials" 335 | 336 | fi 337 | 338 | # Save server settings 339 | cat <<- EOF > $DATA_DIR/params 340 | SERVER_TYPE=${SERVER_TYPE} 341 | SERVER_PUB_IP=${SERVER_PUB_IP} 342 | USE_TLS=${USE_TLS} 343 | UPSTREAM_PUB_IP=${UPSTREAM_PUB_IP} 344 | BRIDGE_PUB_ADDRESS=${BRIDGE_PUB_ADDRESS} 345 | UUID=${UUID} 346 | SHADOWSOCKS_PASSWORD=${SHADOWSOCKS_PASSWORD} 347 | EOF 348 | 349 | } 350 | 351 | function showClientConfig() { 352 | cat $DATA_DIR/v2ray-defaultUser 353 | } 354 | 355 | function uninstallV2ray() { 356 | until [[ ${CONFIRM_UNINSTALL} =~ ^(y|n)$ ]]; do 357 | read -rp "Uninstalling, are you sure? (y/n) " -e -i "n" CONFIRM_UNINSTALL 358 | done 359 | if [[ $CONFIRM_UNINSTALL == "y" ]]; then 360 | rm -rf $DATA_DIR 361 | docker-compose --project-directory v2ray-upstream-server down 362 | colorEcho ${GREEN} "Uninstalled V2Ray from $SERVER_TYPE Server." 363 | fi 364 | 365 | } 366 | 367 | function checkContainerRunning() { 368 | if [[ $1 == 'v2ray_upstream' ]]; then 369 | PROJECT_DIR='v2ray-upstream-server' 370 | elif [[ $1 == 'haproxy_bridge' ]]; then 371 | PROJECT_DIR='haproxy-bridge-server' 372 | fi 373 | 374 | CID=$(docker ps --filter=name=$1 --filter=status=running -q) 375 | if [[ -z $CID ]]; then 376 | colorEcho ${RED} "Container $1 does not exist or is not running. Container logs: " 377 | docker-compose --project-directory $PROJECT_DIR logs 378 | colorEcho ${YELLOW} "If you keep seeing this as startup, try uninstalling the service and install again\n\n" 379 | 380 | # exit unless second parameter is 'noexit' 381 | [[ $2 == "noexit" ]] || exit 1 382 | fi 383 | } 384 | 385 | function upstreamManageMenu() { 386 | echo "Welcome to the V2Ray-install!" 387 | echo "The git repository is available at: https://github.com/UZziell/v2ray-haproxy-docker" 388 | echo "" 389 | echo "It looks like V2ray is already installed." 390 | echo "" 391 | echo "What do you want to do?" 392 | echo " 1) Show client configs (QRCode and URLs)" 393 | echo " 2) Uninstall V2Ray and all configs" 394 | echo " 3) Exit" 395 | until [[ ${MENU_OPTION} =~ ^[1-3]$ ]]; do 396 | read -rp "Select an option [1-3]: " MENU_OPTION 397 | done 398 | case "${MENU_OPTION}" in 399 | 1) 400 | showClientConfig 401 | ;; 402 | 2) 403 | uninstallV2ray 404 | ;; 405 | 3) 406 | exit 0 407 | ;; 408 | 409 | # TODO 410 | # newClient 411 | # deleteClient 412 | 413 | esac 414 | } 415 | 416 | # Check for root, virt, OS... 417 | initialCheck 418 | 419 | # Check if V2Ray is already installed and load params 420 | if [[ -e $DATA_DIR/params ]]; then 421 | source $DATA_DIR/params 422 | if [[ $SERVER_TYPE == "upstream" ]]; then 423 | checkContainerRunning 'v2ray_upstream' 'noexit' 424 | upstreamManageMenu 425 | elif [[ $SERVER_TYPE == "bridge" ]]; then 426 | checkContainerRunning 'haproxy_bridge' 'noexit' 427 | colorEcho ${GREEN} "HAProxy is running and '$UPSTREAM_PUB_IP' is configured as it's Upstream" 428 | until [[ ${UNINSTALL_BRIDGE} =~ ^(y|n)$ ]]; do 429 | read -rp "Do you want to uninstall it? (y/n) " -e -i "n" UNINSTALL_BRIDGE 430 | done 431 | if [[ $UNINSTALL_BRIDGE == "y" ]]; then 432 | docker-compose --project-directory haproxy-bridge-server down && rm -rf $DATA_DIR 433 | colorEcho ${GREEN} "Uninstalled HAProxy from Bridge Server." 434 | fi 435 | fi 436 | 437 | elif [[ -n $(docker-compose --project-directory haproxy-bridge-server ps -q) ]] || [[ -n $(docker-compose --project-directory v2ray-upstream-server ps -q) ]]; then 438 | colorEcho ${YELLOW} "It looks like you have executed the script before but the setup was not finished!" 439 | until [[ ${REMOVE_RUNNING_CONTAINER} =~ ^(y|n)$ ]]; do 440 | read -rp "Stop and delete running container?(running container is v2ray or haproxy or maybe even both) (y/n) " -e -i "y" REMOVE_RUNNING_CONTAINER 441 | done 442 | if [[ $REMOVE_RUNNING_CONTAINER == "y" ]]; then 443 | docker-compose --project-directory haproxy-bridge-server down 444 | docker-compose --project-directory v2ray-upstream-server down 445 | colorEcho ${GREEN} "Stopped and removed. Proceeding..." 446 | installConfigRun 447 | else 448 | colorEcho ${GREEN} "So do it manually and re-execute the install script" 449 | exit 1 450 | fi 451 | 452 | else 453 | installConfigRun 454 | fi 455 | --------------------------------------------------------------------------------