From be78e9ec32a006fbb533913f87c81b72deebb5c5 Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Mon, 13 Sep 2021 16:35:17 +1000 Subject: [PATCH] Multi-location Nginx proxy support --- Dockerfile.amd64 | 9 +- Dockerfile.arm | 9 +- Dockerfile.arm64 | 9 +- grpc.tpl | 9 ++ run.sh | 62 ++++++--- server-ltpg.sh | 80 +++++++++++ server-ltpw.sh | 132 ++++++++++++++++++ server-lttg.sh | 56 ++------ server-lttw.sh | 4 +- server-mtpw.sh | 132 ++++++++++++++++++ server-nginx.sh | 143 ++++++++++++++++++++ server-ttpw.sh | 136 +++++++++++++++++++ site-ssl-grpc.conf.tpl => site-ssl.conf.tpl | 10 +- ws.tpl | 13 ++ 14 files changed, 731 insertions(+), 73 deletions(-) create mode 100644 grpc.tpl create mode 100755 server-ltpg.sh create mode 100755 server-ltpw.sh create mode 100755 server-mtpw.sh create mode 100755 server-nginx.sh create mode 100755 server-ttpw.sh rename site-ssl-grpc.conf.tpl => site-ssl.conf.tpl (62%) create mode 100644 ws.tpl diff --git a/Dockerfile.amd64 b/Dockerfile.amd64 index 0fd6bd1..ff7a16e 100644 --- a/Dockerfile.amd64 +++ b/Dockerfile.amd64 @@ -18,16 +18,23 @@ RUN apk update && apk add bash nginx openssl curl socat jq moreutils RUN cd /root; curl -sSL "https://github.com/acmesh-official/acme.sh/archive/refs/tags/2.9.0.tar.gz"|tar zxvf - RUN cd /root; mv acme.sh-2.9.0 .acme.sh -COPY site-ssl-grpc.conf.tpl /etc/nginx/http.d/ +COPY site-ssl.conf.tpl /etc/nginx/http.d/ +COPY grpc.tpl /etc/nginx/http.d/ +COPY ws.tpl /etc/nginx/http.d/ ADD run.sh /run.sh ADD server-ltx.sh /server-ltx.sh ADD server-ltt.sh /server-ltt.sh ADD server-lttw.sh /server-lttw.sh +ADD server-ltpw.sh /server-ltpw.sh ADD server-mtt.sh /server-mtt.sh ADD server-mttw.sh /server-mttw.sh +ADD server-mtpw.sh /server-mtpw.sh ADD server-ttt.sh /server-ttt.sh ADD server-tttw.sh /server-tttw.sh +ADD server-ttpw.sh /server-ttpw.sh ADD server-lttg.sh /server-lttg.sh +ADD server-ltpg.sh /server-ltpg.sh +ADD server-nginx.sh /server-nginx.sh RUN chmod 755 /*.sh diff --git a/Dockerfile.arm b/Dockerfile.arm index 06f86bc..5dc6d04 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -18,16 +18,23 @@ RUN apk update && apk add bash nginx openssl curl socat jq moreutils RUN cd /root; curl -sSL "https://github.com/acmesh-official/acme.sh/archive/refs/tags/2.9.0.tar.gz"|tar zxvf - RUN cd /root; mv acme.sh-2.9.0 .acme.sh -COPY site-ssl-grpc.conf.tpl /etc/nginx/http.d/ +COPY site-ssl.conf.tpl /etc/nginx/http.d/ +COPY grpc.tpl /etc/nginx/http.d/ +COPY ws.tpl /etc/nginx/http.d/ ADD run.sh /run.sh ADD server-ltx.sh /server-ltx.sh ADD server-ltt.sh /server-ltt.sh ADD server-lttw.sh /server-lttw.sh +ADD server-ltpw.sh /server-ltpw.sh ADD server-mtt.sh /server-mtt.sh ADD server-mttw.sh /server-mttw.sh +ADD server-mtpw.sh /server-mtpw.sh ADD server-ttt.sh /server-ttt.sh ADD server-tttw.sh /server-tttw.sh +ADD server-ttpw.sh /server-ttpw.sh ADD server-lttg.sh /server-lttg.sh +ADD server-ltpg.sh /server-ltpg.sh +ADD server-nginx.sh /server-nginx.sh RUN chmod 755 /*.sh diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index 24295f7..cc67a02 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -18,16 +18,23 @@ RUN apk update && apk add bash nginx openssl curl socat jq moreutils RUN cd /root; curl -sSL "https://github.com/acmesh-official/acme.sh/archive/refs/tags/2.9.0.tar.gz"|tar zxvf - RUN cd /root; mv acme.sh-2.9.0 .acme.sh -COPY site-ssl-grpc.conf.tpl /etc/nginx/http.d/ +COPY site-ssl.conf.tpl /etc/nginx/http.d/ +COPY grpc.tpl /etc/nginx/http.d/ +COPY ws.tpl /etc/nginx/http.d/ ADD run.sh /run.sh ADD server-ltx.sh /server-ltx.sh ADD server-ltt.sh /server-ltt.sh ADD server-lttw.sh /server-lttw.sh +ADD server-ltpw.sh /server-ltpw.sh ADD server-mtt.sh /server-mtt.sh ADD server-mttw.sh /server-mttw.sh +ADD server-mtpw.sh /server-mtpw.sh ADD server-ttt.sh /server-ttt.sh ADD server-tttw.sh /server-tttw.sh +ADD server-ttpw.sh /server-ttpw.sh ADD server-lttg.sh /server-lttg.sh +ADD server-ltpg.sh /server-ltpg.sh +ADD server-nginx.sh /server-nginx.sh RUN chmod 755 /*.sh diff --git a/grpc.tpl b/grpc.tpl new file mode 100644 index 0000000..eb98fed --- /dev/null +++ b/grpc.tpl @@ -0,0 +1,9 @@ + location LOCATION { + if ($content_type !~ "application/grpc") { + return 404; + } + client_max_body_size 0; + client_body_timeout 1071906480m; + grpc_read_timeout 1071906480m; + grpc_pass grpc://127.0.0.1:PORT; + } \ No newline at end of file diff --git a/run.sh b/run.sh index 0cd9a00..6e3373e 100755 --- a/run.sh +++ b/run.sh @@ -6,24 +6,30 @@ XCONF=/tmp/server-xray.json usage() { echo "server-xray " - echo " --ltx [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" - echo " --ltt [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" - echo " --lttw [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" - echo " --lttg [p=443,]d=domain.com,u=id[:level[:email]],s=/svcpath,g=grpcport" - echo " --mtt [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" - echo " --mttw [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" - echo " --ttt [p=443,]d=domain.com,u=psw[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" - echo " --tttw [p=443,]d=domain.com,u=psw[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" -# echo " --ssa [port=443,]user=password1:method1[,user=password2:method2]" -# echo " --sst [port=443,]user=passwd,method=xxxx" - echo " -k|--hook [Optional] DDNS update or notifing URL to be hit" - echo " -r|--request-domain [Optional] Domain name to request for letsencrypt cert" - echo " -c|--cert-path [Optional] Reading TLS certs from folder //" - echo " -i|--stdin [Optional] Read config from stdin instead of auto generation" - echo " -d|--debug [Optional] Start in debug mode with verbose output" + echo " --ltx [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" + echo " --ltt [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" + echo " --lttw [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" + echo " --ltpw [p=443,]u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" + echo " --lttg [p=443,]d=domain.com,u=id[:level[:email]],s=/svcpath" + echo " --ltpg [p=443,]u=id[:level[:email]],s=/svcpath" + echo " --mtt [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" + echo " --mttw [p=443,]d=domain.com,u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" + echo " --mtpw [p=443,]u=id[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" + echo " --ttt [p=443,]d=domain.com,u=psw[:level[:email]][,f=[fb-host]:fb-port:[fb-path]]" + echo " --tttw [p=443,]d=domain.com,u=psw[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" + echo " --ttpw [p=443,]u=psw[:level[:email]][,f=[fb-host]:fb-port:[fb-path]],w=/webpath" +# echo " --ssa [port=443,]user=password1:method1[,user=password2:method2]" +# echo " --sst [port=443,]user=passwd,method=xxxx" + echo " --ng-opt [p=443,]d=domain.com" + echo " --ng-proxy [h=127.0.0.1,]p=8443,l=location,n=ws|grpc" + echo " -k|--hook [Optional] DDNS update or notifing URL to be hit" + echo " -r|--request-domain [Optional] Domain name to request for letsencrypt cert" + echo " -c|--cert-path [Optional] Reading TLS certs from folder //" + echo " -i|--stdin [Optional] Read config from stdin instead of auto generation" + echo " -d|--debug [Optional] Start in debug mode with verbose output" } -TEMP=`getopt -o k:r:c:di --long hook:,request-domain:,cert-path:,ltx:,ltt:,lttw:,mtt:,mttw:,ttt:,tttw:,lttg:,ssa:,sst:stdin,debug -n "$0" -- $@` +TEMP=`getopt -o k:r:c:di --long hook:,request-domain:,cert-path:,ltx:,ltt:,lttw:,ltpw:,mtt:,mttw:,mtpw:,ttt:,tttw:,ttpw:,lttg:,ltpg:,ssa:,sst:,ng-opt:,ng-proxy:,stdin,debug -n "$0" -- $@` if [ $? != 0 ] ; then usage; exit 1 ; fi eval set -- "$TEMP" @@ -49,11 +55,19 @@ while true ; do DEBUG=1 shift 1 ;; - --ltx|--ltt|--lttw|--lttg|--mtt|--mttw|--ttt|--tttw) + --ltx|--ltt|--lttw|--ltpw|--lttg|--ltpg|--mtt|--mttw|--mtpw|--ttt|--tttw|--ttpw) if [ "$1" = "--lttg" ]; then NGINX=1; fi SVC=`echo $1|tr -d '\-\-'` SVCMD+=("${DIR}server-${SVC}.sh $2") shift 2 + ;; + --ng-opt) + NGOPT=$2 + shift 2 + ;; + --ng-proxy) + NGPROXY+=("$2") + shift 2 ;; --) shift @@ -117,14 +131,26 @@ if [ -n "${SVCMD}" ]; then exit 1 fi done + if [ "${DEBUG}" = "1" ]; then cat $XCONF |jq '.log.loglevel |="debug"' |sponge $XCONF echo cat $XCONF echo fi - if [ "${NGINX}" = "1" ]; then nginx; fi + + if [ -n "${NGOPT}" ]; then + ngcmd="${DIR}server-nginx.sh --ng-opt ${NGOPT},$xopt" + for ngproxy in "${NGPROXY[@]}" + do + ngcmd="${ngcmd} --ng-proxy ${ngproxy}" + done + $ngcmd + nginx; + fi + exec /usr/local/bin/xray -c $XCONF + else if [ "${STDINCONF}" = "1" ]; then exec /usr/local/bin/xray diff --git a/server-ltpg.sh b/server-ltpg.sh new file mode 100755 index 0000000..3131277 --- /dev/null +++ b/server-ltpg.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +usage() { + echo "Usage: server-lttg ,,," +} + +options=(`echo $1 |tr ',' ' '`) +for option in "${options[@]}" +do + kv=(`echo $option |tr '=' ' '`) + case "${kv[0]}" in + x|xconf) + xconf="${kv[1]}" + ;; + p|port) + port="${kv[1]}" + ;; + u|user) + xuser+=("${kv[1]}") + ;; + s|service) + service="${kv[1]}" + ;; + esac +done + +if [ -z "${xconf}" ]; then + echo "Error: xconf undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if [ -z "${xuser}" ]; then + echo "Error: user undefined." + usage + exit 1 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +XCONF=$xconf +cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"vless", "settings":{"clients":[]}}]' |sponge $XCONF + +for xu in "${xuser[@]}" +do + IFS=':' + uopt=(${xu}) + uopt=(${uopt[@]}) + + if [ -z "${uopt[0]}" ]; then + echo "Incorrect user format: ${xu}" + echo "Correct user format: user=[:level:email]" + echo "Like: user=myid:0:nobody@g.cn" + echo "Like: user=myid::nobody@g.cn" + echo "Like: user=myid:0" + echo "Like: user=myid" + exit 1 + fi + if [ -z "${uopt[1]}" ]; then + uopt[1]=0 + fi + if [ -z "${uopt[2]}" ]; then + uopt[2]="nobody@g.cn" + fi + cat $XCONF |jq --arg port "${port}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \ +|sponge $XCONF + +cat $XCONF |jq --arg port "${port}" --arg service "${service}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"grpc", "grpcSettings":{"serviceName":$service}, "security":"none"} ' \ +|sponge $XCONF diff --git a/server-ltpw.sh b/server-ltpw.sh new file mode 100755 index 0000000..6ca4351 --- /dev/null +++ b/server-ltpw.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +usage() { + echo "Usage: server-ltpw ,,,[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]" +} + +options=(`echo $1 |tr ',' ' '`) +for option in "${options[@]}" +do + kv=(`echo $option |tr '=' ' '`) + case "${kv[0]}" in + x|xconf) + xconf="${kv[1]}" + ;; + p|port) + port="${kv[1]}" + ;; + u|user) + xuser+=("${kv[1]}") + ;; + w|wpath) + wspath="${kv[1]}" + ;; + f|fallback) + fallback+=("${kv[1]}") + ;; + esac +done + +if [ -z "${xconf}" ]; then + echo "Error: xconf undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if [ -z "${xuser}" ]; then + echo "Error: user undefined." + usage + exit 1 +fi + +if [ -z "${wspath}" ]; then + echo "Error: wspath undefined." + usage + exit 1 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +XCONF=$xconf +cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"vless", "settings":{"clients":[]}}]' |sponge $XCONF + +for xu in "${xuser[@]}" +do + IFS=':' + uopt=(${xu}) + uopt=(${uopt[@]}) + + if [ -z "${uopt[0]}" ]; then + echo "Incorrect user format: ${xu}" + echo "Correct user format: user=[:level:email]" + echo "Like: user=myid:0:nobody@g.cn" + echo "Like: user=myid::nobody@g.cn" + echo "Like: user=myid:0" + echo "Like: user=myid" + exit 1 + fi + if [ -z "${uopt[1]}" ]; then + uopt[1]=0 + fi + if [ -z "${uopt[2]}" ]; then + uopt[2]="nobody@g.cn" + fi + cat $XCONF |jq --arg port "${port}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \ +|sponge $XCONF + +for fb in "${fallback[@]}" +do + IFS=':' + fopt=(${fb}) + fopt=(${fopt[@]}) + + fhost="${fopt[0]}" + fport="${fopt[1]}" + fpath="${fopt[2]}" + + if [ -z "${fport}" ]; then + echo "Incorrect fallback format: ${fb}" + echo "Correct fallback: fallback=[host]<:port>[:path]" + echo "Like: fallback=baidu.com:443:/websocket" + echo "Like: fallback=:1443:/websocket" + echo "Like: fallback=:1443" + exit 1 + fi + + if [ -z "${fhost}" ]; then + if [ -z "${fpath}" ]; then + Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "xver":1}'` + else + Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "path":$fpath, "xver":1}'` + fi + else + if [ -z "${fpath}" ]; then + fdest="${fhost}:${fport}" + Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "xver":1}'` + else + Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "path":$fpath, "xver":1}'` + fi + fi + + cat $XCONF |jq --arg port "${port}" --argjson jfallback "$Jfallback" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.fallbacks ) += [ $jfallback ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"ws", "security":"none" } ' \ +|sponge $XCONF + +cat $XCONF |jq --arg port "${port}" --arg wspath "${wspath}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"wsSettings":{"path":$wspath}} ' \ +|sponge $XCONF diff --git a/server-lttg.sh b/server-lttg.sh index 4e05a65..0462287 100755 --- a/server-lttg.sh +++ b/server-lttg.sh @@ -1,7 +1,7 @@ #!/bin/bash usage() { - echo "Usage: server-lttg ,,,,,," + echo "Usage: server-lttg ,,,,," } options=(`echo $1 |tr ',' ' '`) @@ -24,9 +24,6 @@ do u|user) xuser+=("${kv[1]}") ;; - g|gport) - gport="${kv[1]}" - ;; s|service) service="${kv[1]}" ;; @@ -49,12 +46,6 @@ if [ -z "${port}" ]; then port=443 fi -if [ -z "${gport}" ]; then - echo "Error: gport undefined." - usage - exit 1 -fi - if [ -z "${domain}" ]; then echo "Error: domain undefined." usage @@ -68,10 +59,9 @@ if [ -z "${xuser}" ]; then fi if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi -if ! [ "${gport}" -eq "${gport}" ] 2>/dev/null; then >&2 echo "Gport number must be numeric"; exit 1; fi XCONF=$xconf -cat $XCONF |jq --arg gport "${gport}" '.inbounds +=[{"port":($gport|tonumber), "protocol":"vless", "settings":{"clients":[]}}]' |sponge $XCONF +cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"vless", "settings":{"clients":[]}}]' |sponge $XCONF for xu in "${xuser[@]}" do @@ -94,17 +84,21 @@ do if [ -z "${uopt[2]}" ]; then uopt[2]="nobody@g.cn" fi - cat $XCONF |jq --arg gport "${gport}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \ - '( .inbounds[] | select(.port == ($gport|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \ + cat $XCONF |jq --arg port "${port}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \ |sponge $XCONF done -cat $XCONF |jq --arg gport "${gport}" \ -'( .inbounds[] | select(.port == ($gport|tonumber)) | .settings.decryption ) += "none" ' \ +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \ |sponge $XCONF -cat $XCONF |jq --arg gport "${gport}" --arg service "${service}" \ -'( .inbounds[] | select(.port == ($gport|tonumber)) | .streamSettings ) += {"network":"grpc", "grpcSettings":{"serviceName":$service} } ' \ +cat $XCONF |jq --arg port "${port}" --arg service "${service}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"grpc", "grpcSettings":{"serviceName":$service}, "security":"tls"} ' \ +|sponge $XCONF + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"tlsSettings":{"alpn":["http/2"]}} ' \ |sponge $XCONF for certroot in "${certpath[@]}" @@ -122,26 +116,6 @@ if [ ! -f "${fullchain}" ] || [ ! -f "${prvkey}" ]; then exit 2 fi -# Running as root to enable low port listening. Necessary for Fargate or k8s. -sed -i 's/^user nginx;$/user root;/g' /etc/nginx/nginx.conf -mkdir -p /run/nginx/ - -cd /etc/nginx/http.d/ - -if [ -f /etc/nginx/http.d/default.conf ]; then - mv default.conf default.conf.disable -fi - -TPL="site-ssl-grpc.conf.tpl" - -ESC_CERTFILE=$(printf '%s\n' "${fullchain}" | sed -e 's/[]\/$*.^[]/\\&/g') -ESC_PRVKEYFILE=$(printf '%s\n' "${prvkey}" | sed -e 's/[]\/$*.^[]/\\&/g') -ESC_GSVC=$(printf '%s\n' "${service}" | sed -e 's/[]\/$*.^[]/\\&/g') -cat ${TPL} \ - | sed "s/CERTFILE/${ESC_CERTFILE}/g" \ - | sed "s/PRVKEYFILE/${ESC_PRVKEYFILE}/g" \ - | sed "s/NGDOMAIN/${domain}/g" \ - | sed "s/NGPORT/${port}/g" \ - | sed "s/GPORT/${gport}/g" \ - | sed "s/GSVC/${ESC_GSVC}/g" \ - >site-xray.conf +cat $XCONF |jq --arg port "${port}" --arg fullchain "${fullchain}" --arg prvkey "${prvkey}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings.tlsSettings ) += {"certificates":[{"certificateFile":$fullchain, "keyFile":$prvkey}]} ' \ +|sponge $XCONF diff --git a/server-lttw.sh b/server-lttw.sh index d7778ab..91ef563 100755 --- a/server-lttw.sh +++ b/server-lttw.sh @@ -142,11 +142,11 @@ do done cat $XCONF |jq --arg port "${port}" \ -'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"ws", "security":"tls" } ' \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"ws", "security":"tls"} ' \ |sponge $XCONF cat $XCONF |jq --arg port "${port}" \ -'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"tlsSettings":{"alpn":["http/1.1"]} } ' \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"tlsSettings":{"alpn":["http/1.1"]}} ' \ |sponge $XCONF cat $XCONF |jq --arg port "${port}" --arg wspath "${wspath}" \ diff --git a/server-mtpw.sh b/server-mtpw.sh new file mode 100755 index 0000000..69a9cba --- /dev/null +++ b/server-mtpw.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +usage() { + echo "Usage: server-mtpw ,,,[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]" +} + +options=(`echo $1 |tr ',' ' '`) +for option in "${options[@]}" +do + kv=(`echo $option |tr '=' ' '`) + case "${kv[0]}" in + x|xconf) + xconf="${kv[1]}" + ;; + p|port) + port="${kv[1]}" + ;; + u|user) + xuser+=("${kv[1]}") + ;; + w|wpath) + wspath="${kv[1]}" + ;; + f|fallback) + fallback+=("${kv[1]}") + ;; + esac +done + +if [ -z "${xconf}" ]; then + echo "Error: xconf undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if [ -z "${xuser}" ]; then + echo "Error: user undefined." + usage + exit 1 +fi + +if [ -z "${wspath}" ]; then + echo "Error: wspath undefined." + usage + exit 1 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +XCONF=$xconf +cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"vmess", "settings":{"clients":[]}}]' |sponge $XCONF + +for xu in "${xuser[@]}" +do + IFS=':' + uopt=(${xu}) + uopt=(${uopt[@]}) + + if [ -z "${uopt[0]}" ]; then + echo "Incorrect user format: ${xu}" + echo "Correct user format: user=[:level:email]" + echo "Like: user=myid:0:nobody@g.cn" + echo "Like: user=myid::nobody@g.cn" + echo "Like: user=myid:0" + echo "Like: user=myid" + exit 1 + fi + if [ -z "${uopt[1]}" ]; then + uopt[1]=0 + fi + if [ -z "${uopt[2]}" ]; then + uopt[2]="nobody@g.cn" + fi + cat $XCONF |jq --arg port "${port}" --arg uid "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"id":$uid, "level":($level|tonumber), "email":$email} ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \ +|sponge $XCONF + +for fb in "${fallback[@]}" +do + IFS=':' + fopt=(${fb}) + fopt=(${fopt[@]}) + + fhost="${fopt[0]}" + fport="${fopt[1]}" + fpath="${fopt[2]}" + + if [ -z "${fport}" ]; then + echo "Incorrect fallback format: ${fb}" + echo "Correct fallback: fallback=[host]<:port>[:path]" + echo "Like: fallback=baidu.com:443:/websocket" + echo "Like: fallback=:1443:/websocket" + echo "Like: fallback=:1443" + exit 1 + fi + + if [ -z "${fhost}" ]; then + if [ -z "${fpath}" ]; then + Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "xver":1}'` + else + Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "path":$fpath, "xver":1}'` + fi + else + if [ -z "${fpath}" ]; then + fdest="${fhost}:${fport}" + Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "xver":1}'` + else + Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "path":$fpath, "xver":1}'` + fi + fi + + cat $XCONF |jq --arg port "${port}" --argjson jfallback "$Jfallback" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.fallbacks ) += [ $jfallback ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"ws", "security":"none" } ' \ +|sponge $XCONF + +cat $XCONF |jq --arg port "${port}" --arg wspath "${wspath}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"wsSettings":{"path":$wspath}} ' \ +|sponge $XCONF diff --git a/server-nginx.sh b/server-nginx.sh new file mode 100755 index 0000000..7f562b8 --- /dev/null +++ b/server-nginx.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +DIR=`dirname $0` +DIR="$(cd $DIR; pwd)" + +usage() { + echo "Usage: server-nginx --ng-opt --ng-proxy " +} + +TEMP=`getopt -o o:x: --long ng-opt:,ng-proxy: -n "$0" -- $@` +if [ $? != 0 ] ; then usage; exit 1 ; fi + +eval set -- "$TEMP" +while true ; do + case "$1" in + -o|--ng-opt) + NGOPT="$2" + shift 2 + ;; + -x|--ng-proxy) + NGPROXY+=("$2") + shift 2 + ;; + --) + shift + break + ;; + *) + echo "Unrecogonised opt: $1" + usage; + exit 1 + ;; + esac +done + +options=(`echo $NGOPT |tr ',' ' '`) +for option in "${options[@]}" +do + kv=(`echo $option |tr '=' ' '`) + case "${kv[0]}" in + c|certpath) + certpath+=("${kv[1]}") + ;; + p|port) + port="${kv[1]}" + ;; + d|domain) + domain="${kv[1]}" + ;; + esac +done + +if [ -z "${certpath}" ]; then + echo "Error: certpath undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if [ -z "${domain}" ]; then + echo "Error: domain undefined." + usage + exit 1 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +for certroot in "${certpath[@]}" +do + if [ -f "${certroot}/${domain}/fullchain.cer" ] && [ -f "${certroot}/${domain}/${domain}.key" ]; then + fullchain="${certroot}/${domain}/fullchain.cer" + prvkey="${certroot}/${domain}/${domain}.key" + break + fi +done + +if [ ! -f "${fullchain}" ] || [ ! -f "${prvkey}" ]; then + echo "TLS cert missing?" + echo "Abort." + exit 2 +fi + +# Running as root to enable low port listening. Necessary for Fargate or k8s. +sed -i 's/^user nginx;$/user root;/g' /etc/nginx/nginx.conf +mkdir -p /run/nginx/ + +cd /etc/nginx/http.d/ + +if [ -f /etc/nginx/http.d/default.conf ]; then + mv default.conf default.conf.disable +fi + +TPL="site-ssl.conf.tpl" + +ESC_CERTFILE=$(printf '%s\n' "${fullchain}" | sed -e 's/[]\/$*.^[]/\\&/g') +ESC_PRVKEYFILE=$(printf '%s\n' "${prvkey}" | sed -e 's/[]\/$*.^[]/\\&/g') +cat ${TPL} \ + | sed "s/CERTFILE/${ESC_CERTFILE}/g" \ + | sed "s/PRVKEYFILE/${ESC_PRVKEYFILE}/g" \ + | sed "s/NGDOMAIN/${domain}/g" \ + | sed "s/NGPORT/${port}/g" \ + >site-xray.conf + +for ngproxy in "${NGPROXY[@]}" +do + options=(`echo $ngproxy |tr ',' ' '`) + for option in "${options[@]}" + do + kv=(`echo $option |tr '=' ' '`) + case "${kv[0]}" in + h|host) + xhost="${kv[1]}" + ;; + p|port) + xport="${kv[1]}" + ;; + l|location) + xlocation="${kv[1]}" + ;; + n|network) + xnetwork="${kv[1]}" + ;; + esac + done + + # Replace the last(only) single line '}' with specific tpl file, hence insert a new section into the Nginx config file + case "${xnetwork}" in + ws|websocket) + sed -i -e "/^\}$/r ws.tpl" -e "/^\}$/d" site-xray.conf + ;; + grpc) + sed -i -e "/^\}$/r grpc.tpl" -e "/^\}$/d" site-xray.conf + ;; + esac + # Then add '}' to the end of the Nginx config file + echo -e "\n}" >> site-xray.conf + ESC_LOCATION=$(printf '%s\n' "${xlocation}" | sed -e 's/[]\/$*.^[]/\\&/g') + sed -i "s/PORT/${xport}/g" site-xray.conf + sed -i "s/LOCATION/${ESC_LOCATION}/g" site-xray.conf +done diff --git a/server-ttpw.sh b/server-ttpw.sh new file mode 100755 index 0000000..b224446 --- /dev/null +++ b/server-ttpw.sh @@ -0,0 +1,136 @@ +#!/bin/bash + +usage() { + echo "Usage: server-ttpw ,,[,fallback=www.baidu.com:443:/html][,fallback=:2443:/websocket2]" +} + +options=(`echo $1 |tr ',' ' '`) +for option in "${options[@]}" +do + kv=(`echo $option |tr '=' ' '`) + case "${kv[0]}" in + x|xconf) + xconf="${kv[1]}" + ;; + p|port) + port="${kv[1]}" + ;; + u|user) + xuser+=("${kv[1]}") + ;; + w|wpath) + wspath="${kv[1]}" + ;; + f|fallback) + fallback+=("${kv[1]}") + ;; + esac +done + +if [ -z "${xconf}" ]; then + echo "Error: xconf undefined." + usage + exit 1 +fi + +if [ -z "${port}" ]; then + port=443 +fi + +if [ -z "${xuser}" ]; then + echo "Error: user undefined." + usage + exit 1 +fi + +if [ -z "${wspath}" ]; then + echo "Error: wspath undefined." + usage + exit 1 +fi + +if ! [ "${port}" -eq "${port}" ] 2>/dev/null; then >&2 echo "Port number must be numeric"; exit 1; fi + +XCONF=$xconf +cat $XCONF |jq --arg port "${port}" '.inbounds +=[{"port":($port|tonumber), "protocol":"trojan", "settings":{"clients":[]}}]' |sponge $XCONF + +for xu in "${xuser[@]}" +do + IFS=':' + uopt=(${xu}) + uopt=(${uopt[@]}) + + if [ -z "${uopt[0]}" ]; then + echo "Incorrect user format: ${xu}" + echo "Correct user format: user=password[:level[:email]" + echo "Like: user=mypass:0:me@g.cn" + echo "Like: user=mypass::me@g.cn" + echo "Like: user=mypass:0" + echo "Like: user=mypass" + exit 1 + fi + if [ -z "${uopt[1]}" ]; then + uopt[1]=0 + fi + if [ -z "${uopt[2]}" ]; then + uopt[2]="nobody@g.cn" + fi + cat $XCONF |jq --arg port "${port}" --arg pass "${uopt[0]}" --arg level "${uopt[1]}" --arg email "${uopt[2]}" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.clients ) += [ {"password":$pass, "level":($level|tonumber), "email":$email} ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .settings.decryption ) += "none" ' \ +|sponge $XCONF + +for fb in "${fallback[@]}" +do + IFS=':' + fopt=(${fb}) + fopt=(${fopt[@]}) + + fhost="${fopt[0]}" + fport="${fopt[1]}" + fpath="${fopt[2]}" + + if [ -z "${fport}" ]; then + echo "Incorrect fallback format: ${fb}" + echo "Correct fallback: fallback=[host]<:port>[:path]" + echo "Like: fallback=baidu.com:443:/websocket" + echo "Like: fallback=:1443:/websocket" + echo "Like: fallback=:1443" + exit 1 + fi + + if [ -z "${fhost}" ]; then + if [ -z "${fpath}" ]; then + Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "xver":1}'` + else + Jfallback=`echo '{}' |jq --arg fport "${fport}" --arg fpath "${fpath}" '. += {"dest":($fport|tonumber), "path":$fpath, "xver":1}'` + fi + else + if [ -z "${fpath}" ]; then + fdest="${fhost}:${fport}" + Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "xver":1}'` + else + Jfallback=`echo '{}' |jq --arg fdest "${fdest}" --arg fpath "${fpath}" '. += {"dest":$fdest, "path":$fpath, "xver":1}'` + fi + fi + + cat $XCONF |jq --arg port "${port}" --argjson jfallback "$Jfallback" \ + '( .inbounds[] | select(.port == ($port|tonumber)) | .settings.fallbacks ) += [ $jfallback ] ' \ + |sponge $XCONF +done + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"network":"ws", "security":"none" } ' \ +|sponge $XCONF + +cat $XCONF |jq --arg port "${port}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"tlsSettings":{"alpn":["http/1.1"]} } ' \ +|sponge $XCONF + +cat $XCONF |jq --arg port "${port}" --arg wspath "${wspath}" \ +'( .inbounds[] | select(.port == ($port|tonumber)) | .streamSettings ) += {"wsSettings":{"path":$wspath}} ' \ +|sponge $XCONF diff --git a/site-ssl-grpc.conf.tpl b/site-ssl.conf.tpl similarity index 62% rename from site-ssl-grpc.conf.tpl rename to site-ssl.conf.tpl index ffd78be..87c9105 100644 --- a/site-ssl-grpc.conf.tpl +++ b/site-ssl.conf.tpl @@ -13,13 +13,5 @@ server { location / { return 404; } - location GSVC { - if ($content_type !~ "application/grpc") { - return 404; - } - client_max_body_size 0; - client_body_timeout 1071906480m; - grpc_read_timeout 1071906480m; - grpc_pass grpc://127.0.0.1:GPORT; - } + } \ No newline at end of file diff --git a/ws.tpl b/ws.tpl new file mode 100644 index 0000000..6737ad3 --- /dev/null +++ b/ws.tpl @@ -0,0 +1,13 @@ + location LOCATION { + if ($http_upgrade != "websocket") { + return 404; + } + proxy_redirect off; + proxy_pass http://127.0.0.1:PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } \ No newline at end of file