原理
原理是创建两个docker容器,一个是nginx,一个是ss,用nginx反代ss实现流量转发,nginx绑定域名并用Let`s Encrypt认证域名绑定Https证书走TLS流量。
功能:
-
认证域名(基于
certbot-nginx
,背后是用的Let's Encrypt实现的认证) -
流量统计(基于
fcgiwrap
,原理是通过Http请求到Nginx,Nginx通过fcgiwrap执行shell脚本,脚本通过分析nginx访问日志进行流量统计) -
添加代理path(基于fcgiwrap)
-
删除代理path(基于fcgiwrap)
欲知更多关于fcgiwrap的信息,请参考fcgiwrap 的简单使用
手动使用
假设代理根path为v2rayRootPath,域名为domain.com
定义变量
domain=domain.com #你的域名
v2rayPath=v2rayRootPath #v兔瑞根路径
sspwd=sspwd #ss密码
ssmethod=chacha20-ietf-poly1305 #ss加密方式
ssport=8388 #ss端口
运行ss容器
docker run -d \
--name ss \
--restart=always \
-e "ARGS=--plugin v2ray-plugin --plugin-opts server;path=/$v2rayPath;loglevel=none" \
-e PASSWORD=$sspwd \
-e SERVER_PORT=$ssport \
-e METHOD=$ssmethod \
-v /etc/localtime:/etc/localtime \
kimoqi/ssv2ray
获取ss的容器(内网)IP
ssip=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ss`
运行nginx容器,映射80/443端口
docker run --name ngx \
--restart=always \
-e v2rayPath=$v2rayPath \
-e domain=$domain \
-e ssipport=${ssip}:${ssport} \
-p 80:80 -p 443:443 \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /etc/ngx:/etc/ngx \
-v /etc/localtime:/etc/localtime \
-d kimoqi/nginx4ss
访问试试是否成功curl http://$domain
域名HTTPS认证
docker exec -it ngx certbot --nginx --register-unsafely-without-email
接下来跟着提示输入就行,最后,访问试试是否成功curl https://$domain
添加代理path
例:添加test
访问https://domain.com/v2rayRootPath/add?test
即可
删除代理path
例:删除test
访问https://domain.com/v2rayRootPath/del?test
即可
流量统计
访问https://domain.com/v2rayRootPath/statis
即可
客户端参数
服务器名称: $domain
服务器端口: 443(切记这里的端口是nginx监听的443端口)
密码: $sspwd
加密方式: chacha20-ietf-poly1305
插件程序: v2ray
插件参数:tls;host=$domain;path=/$v2rayPath
插件
-
安卓:https://github.com/shadowsocks/v2ray-plugin-android/releases
-
IOS:2.1.37版本以上小火箭(shadowrocket)才支持
-
MAC:点击下载小飞机 v1.9.4,此版本需要Mac OS版本大于v10.12,如果不行,请到github进行下载,注意版本需大于 v1.9.0!!!
一键脚本使用
如果SSoverTLS_Adv.sh
和AddDomain.sh
脚本内容失效,直接复制下面的脚本源码
帮助
bash <(curl https://raw.githubusercontent.com/scriptwang/SSoverTLS/master/sh/SSoverTLS_Adv.sh) -h
安装
bash <(curl https://raw.githubusercontent.com/scriptwang/SSoverTLS/master/sh/SSoverTLS_Adv.sh) -i
更新伪站
bash <(curl https://raw.githubusercontent.com/scriptwang/SSoverTLS/master/sh/SSoverTLS_Adv.sh) -w
认证新域名
需要在安装之后认证
bash <(curl https://raw.githubusercontent.com/scriptwang/SSoverTLS/master/sh/AddDomain.sh)
脚本源码SSoverTLS_Adv.sh
此脚本用于实现一键安装,更新伪站的功能,基于docker
#!/bin/bash
# 产生随机密码
function getRandomPwd(){
num=32
if [ $# == 1 ];then
num=$1
fi
echo "$(date +%s)$(shuf -i 10000-65536 -n 1)" | sha256sum | base64 | head -c $num ; echo
}
# url编码
function urlencode() {
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf "$c" | xxd -p -c1 | while read x;do printf "%%%s" "$x";done
esac
done
}
function get_random_webs(){
webs=(
"http://down.cssmoban.com/cssthemes6/sstp_7_Kairos.zip"
"http://down.cssmoban.com/cssthemes6/foun_8_Sinclair.zip"
"http://down.cssmoban.com/cssthemes6/tmag_23_Infinity.zip"
"http://down.cssmoban.com/cssthemes6/dash_1_simple.zip"
"http://down.cssmoban.com/cssthemes6/inva_2_evolo.zip"
"http://down.cssmoban.com/cssthemes6/oplv_9_stage.zip"
"http://down.cssmoban.com/cssthemes6/oplv_2_html5updimension.zip"
"http://down.cssmoban.com/cssthemes6/bpus_10_showtracker.zip"
"http://down.cssmoban.com/cssthemes6/sstp_9_Typerite.zip"
"http://down.cssmoban.com/cssthemes6/resu_1_designer-Portfolio.zip"
"http://down.cssmoban.com/cssthemes6/wsdp_30_invictus.zip"
"http://down.cssmoban.com/cssthemes6/zero_57_zMatcha.zip"
"http://down.cssmoban.com/cssthemes6/zero_54_zHarvest.zip"
"http://down.cssmoban.com/cssthemes6/zero_38_zPhotoGrap.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1927_dag.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1913_daq.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1893_dem.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1876_czx.zip"
"http://down.cssmoban.com/cssthemes6/wsdp_20_union.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1873_cyq.zip"
"http://down.cssmoban.com/cssthemes6/wsdp_11_lambda.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1861_cto.zip"
"http://down.cssmoban.com/cssthemes6/fish_30_rapoo.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1796_cvc.zip"
"http://down.cssmoban.com/cssthemes6/zero_21_zCreative.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1807_cti.zip"
"http://down.cssmoban.com/cssthemes6/mzth_14_unicorn.zip"
"http://down.cssmoban.com/cssthemes6/crui_1_agnes.zip"
"http://down.cssmoban.com/cssthemes6/crui_3_ava.zip"
"http://down.cssmoban.com/cssthemes6/cpts_1845_dcy.zip"
"http://down.cssmoban.com/cssthemes6/tlip_5_material-app.zip"
"http://down.cssmoban.com/cssthemes6/tlip_10_wedding.zip"
"http://down.cssmoban.com/cssthemes6/quar_2_atlantis.zip"
"http://down.cssmoban.com/cssthemes5/tope_11_steak.zip"
"http://down.cssmoban.com/cssthemes1/azmind_1_xb.zip"
"http://down.cssmoban.com/cssthemes4/ft5_67_simple.zip"
"http://down.cssmoban.com/cssthemes3/dgfp_27_hm.zip"
"http://down.cssmoban.com/cssthemes/frt_26.zip"
"http://down.cssmoban.com/cssthemes1/ftmp_135_up.zip"
"http://down.cssmoban.com/cssthemes6/mdbo_14_Landing-Page.zip"
"http://down.cssmoban.com/cssthemes6/tmag_23_Infinity.zip"
"http://down.cssmoban.com/cssthemes6/zero_39_zPinPin.zip"
"http://down.cssmoban.com/cssthemes3/cpts_137_elv.zip"
"http://down.cssmoban.com/cssthemes6/zero_50_zAnimal.zip"
"http://down.cssmoban.com/cssthemes2/dgfp_12_cvh.zip"
"http://down.cssmoban.com/cssthemes3/sbtp_2_fb.zip"
"http://down.cssmoban.com/cssthemes3/npts_10_cvl.zip"
"http://down.cssmoban.com/cssthemes1/ftmp_24.zip"
"http://down.cssmoban.com/cssthemes4/dstp_28_P2.zip"
"http://down.cssmoban.com/cssthemes5/tpmo_520_highway.zip"
"http://down.cssmoban.com/cssthemes5/twts_168_awesplash.zip"
"http://down.cssmoban.com/cssthemes6/wsdp_7_edge.zip"
"http://down.cssmoban.com/cssthemes3/mstp_89_rock4life.zip"
)
RANDOM=$$$(date +%s)
rand=$[$RANDOM % ${#webs[@]}]
echo ${webs[$rand]}
}
# echo $(gen_ss_link_new $ssmethod $sspwd $domain 443 $v2rayPath $(urlencode 中文))
function gen_ss_link_new(){
enc=$1
pwd=$2
host=$3
port=$4
path=$5
mark=$6
# -n flag used to remove newline
# -w 0 ==>> --wrap=COLS Wrap encoded lines after COLS character (default 76). Use 0 to disable line wrapping.
base64encode=$(echo -n "$enc:$pwd" | base64 -w 0)
pluginStr="plugin=v2ray%3btls%3bhost%3d"$host"%3bpath%3d%2f"$path
echo "ss://"$base64encode"@"$host":"$port"/?"$pluginStr"#"$mark
}
# 获取ip
function getIp(){
echo `curl ifconfig.me`
# 如果上面的方法失效,请放开下面的方法,用ifconfig获取外网ip(不一定准确)
#name=""
#if [ $# -ne 0 ];then
# name=$1
#fi
#hash ifconfig 2>/dev/null || {
# yum -y install net-tools 2 > /dev/null
#}
#r=`ifconfig $name | grep "inet.*broadcast.*" | cut -d' ' -f10`
#echo $r
}
# 从域名获取IP
function get_ip_from_domain(){
ADDR=$1
IP=`ping ${ADDR} -c 1 | sed '1{s/[^(]*(//;s/).*//;q}'`
echo ${IP}
}
# 安装相应工具软件
function install_tools(){
hash docker 2>/dev/null || {
# 安装docker
wget -qO- https://get.docker.com/ | bash
}
# 启动并且自启
systemctl restart docker && systemctl enable docker
# install zip
hash zip 2>/dev/null || {
yum -y install zip
}
# install unzip
hash unzip 2>/dev/null || {
yum -y install unzip
}
# install wget if not exists
hash wget 2>/dev/null || {
yum -y install wget
}
# install ifconfig
hash ifconfig 2>/dev/null || {
yum -y install net-tools
}
}
# 修改时间为东八区
function check_datetime(){
# 覆盖系统时间
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 更新系统硬件时间
hwclock
}
# 添加路径
function add_path(){
path=$1
name=$2
# 添加链接
curl https://$domain/$v2rayPath/add?$path 2>/dev/null
# 生成分享链接
echo "当前分享链接为:"
echo ''
export share=$(gen_ss_link_new $ssmethod $sspwd $domain 443 $path $(urlencode $name))
echo $share
echo ''
}
function add_mynet(){
# 先清除所有使用该网络的容器才能删除该网络
docker stop ngx 2>/dev/null
docker rm ngx 2>/dev/null
docker stop ss 2>/dev/null
docker rm ss 2>/dev/null
docker network rm mynet 2>/dev/null
# 创建网络
docker network create --subnet=172.18.0.0/16 mynet
}
function add_ngx(){
# 清理一些资源,避免重复创建出现问题
rm -rf /etc/letsencrypt
rm -rf /etc/ngx
rm -rf /usr/share/nginx
docker stop ngx 2>/dev/null
docker rm ngx 2>/dev/null
# 创建ngx容器
docker run --name ngx \
--network mynet --ip ${nginxip} \
--restart=always \
-e v2rayPath=$v2rayPath \
-e domain=$domain \
-e ssipport=${ssip}:${ssport} \
-p 80:80 -p 443:443 \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /etc/ngx:/etc/ngx \
-v /etc/localtime:/etc/localtime \
-v /usr/share/nginx/html:/usr/share/nginx/html \
-d kimoqi/nginx4ss 2>/dev/null
}
function domain_register(){
# 域名认证
# 自动输入A 1 2 -->> A为同意 1为选择第一个域名 2开启80端口跳转
docker exec -it ngx /bin/sh -c '{ echo "A"; echo "1"; echo "2"; } | /usr/bin/certbot --nginx --register-unsafely-without-email'
}
function add_website(){
# 设置站点模板
path=/usr/share/nginx/html/
# 删除原来的文件
rm -rf ${path}*
# 取出文件名
filename=$(basename $website .zip)
# 下载解压
wget $website -O $path/tmp.zip && unzip $path/tmp.zip -d $path
# 拷贝文件到外面
cp -r $path/$filename/* $path
}
function add_ss(){
# 清理一些资源,避免重复创建出现问题
docker stop ss 2>/dev/null
docker rm ss 2>/dev/null
# 设置带有v2ray插件的shadowsocks
docker run -d \
--network mynet --ip ${ssip} \
--name ss \
--restart=always \
-e "ARGS=--plugin v2ray-plugin --plugin-opts server;path=/$v2rayPath;loglevel=none" \
-e PASSWORD=$sspwd \
-e SERVER_PORT=$ssport \
-e METHOD=$ssmethod \
-v /etc/localtime:/etc/localtime \
kimoqi/ssv2ray 2>/dev/null
}
function define_var(){
export nginxip=172.18.0.2
export ssip=172.18.0.3
# ss使用端口,内网使用,保持默认即可
export ssport=8388
}
function input_domain(){
read -p "请输入域名:" inputdomain
# 检查域名
localip=$(getIp eth0)
domainip=$(get_ip_from_domain ${inputdomain})
if [[ "$localip" != "$domainip" ]];then
echo "该域名 ${inputdomain}指向IP为 ${domainip},非本机IP ${localip},请在域名控制台将域名指向本机IP,脚本退出,再见!"
exit 0
fi
# 定义域名
export domain=$inputdomain
echo '设置域名为 '${domain}
}
function input_v2rayPath(){
read -p "请输入v2ray路径(输入为空则随机生成):" inputpath
if [[ "$inputpath" == "" ]];then
inputpath=$(getRandomPwd 20)
fi
export v2rayPath=$inputpath
echo '设置v2ray路径为 '${v2rayPath}
}
function input_sspwd(){
read -p "请输入shadowsocks密码(输入为空则随机生成):" inputsspwd
if [[ "$inputsspwd" == "" ]];then
inputsspwd=$(getRandomPwd 16)
fi
export sspwd=$inputsspwd
echo '设置shadowsocks密码为 '${sspwd}
}
function input_ssmethod(){
read -p "请输入shadowsocks加密方式(输入为空则默认为chacha20-ietf-poly1305,请务必输入ss支持的加密方式,否则连接不上!):" inputssmethod
if [[ "$inputssmethod" == "" ]];then
inputssmethod=chacha20-ietf-poly1305
fi
export ssmethod=$inputssmethod
echo '设置shadowsocks加密方式为 '${ssmethod}
}
function init_website(){
read -p "请输入站点模板路径(只支持后缀名为.zip的文件),为空将随机选择站点模板(注意:不知道怎么输入直接回车即可!):" inputweb
if [[ "$inputweb" == "" ]];then
inputweb=$(get_random_webs)
fi
# 定义站点模板
export website=$inputweb
echo '设置站点模板为 '${website}
}
# 更新.bashrc
function update_bashrc(){
cat >> ~/.bashrc<<EOF
export domain=${domain}
export v2rayPath=${v2rayPath}
export sspwd=${sspwd}
export ssmethod=${ssmethod}
export website=${website}
export share=${share}
EOF
. ~/.bashrc
}
function print_help(){
echo '帮助信息:'
echo ' -h 打印本信息'
echo ' -i 安装'
echo ' -w 更新伪装站点'
echo "默认分享链接:"${share}
}
function install(){
input_domain
input_v2rayPath
input_sspwd
input_ssmethod
init_website
define_var
echo "安装所需工具中 docker/zip/unzip/wget/ifconfig..."
install_tools 2>/dev/null
echo "调整时间为东八区中..."
check_datetime 2>/dev/null
echo "添加网络中..."
add_mynet 2 > /dev/null
echo "添加shadowsocks容器中..."
add_ss
echo "添加Nginx容器中..."
add_ngx 2>/dev/null
echo "认证域名开始..."
sleep 2
domain_register
echo "认证域名成功..."
echo "添加站点模板中..."
add_website 2>/dev/null
echo "添加站点模板成功!"
print_help
echo "添加分享链接中..."
add_path $domain 默认路径
update_bashrc
}
function update_website(){
init_website
add_website 2>/dev/null
echo '设置完毕!'
}
# 调用入口
if [[ "$1" == "-h" ]];then
# 帮助
print_help
elif [[ "$1" == "-i" ]];then
# 安装
install
elif [[ "$1" == "-w" ]];then
# 更新伪站
update_website
else
echo "没有这个选项${1}"
fi
nginx4ss
这是脚本中用到的nginx的docker镜像,基于alpine,其中的start.sh实现了添加、删除路径、统计流量等功能
DockerFile
FROM nginx:1.17.5-alpine
ENV v2rayPath examplepath
ENV domain example.com
# shadowsocks ip and port
ENV ssipport 127.0.0.1:8388
COPY ./start.sh /root/start.sh
RUN \
apk add --no-cache --virtual .run-deps \
certbot-nginx \
python \
fcgiwrap \
openssh \
sshpass \
&& mkdir -p /etc/ngx/conf.d \
&& echo '0 0,12 * * * sleep 10 && /usr/bin/certbot renew >> /tmp/renew.log' >> /var/spool/cron/crontabs/root \
&& chmod 777 /root/start.sh
EXPOSE 80
ENTRYPOINT ["/root/start.sh"]
start.sh
#!/bin/sh
echo 'starting.....'
rm -rf /var/run/fcgiwrap.socket
echo 'fcgiwrap.socket deled'
fcgiwrap -f -s unix:/var/run/fcgiwrap.socket &
echo 'fcgiwrap.socket started'
sleep 2 # wait fcgiwrap run
chmod a+rw /var/run/fcgiwrap.socket
echo 'chmod fcgiwrap.socket complete'
# 创建脚本
# 添加
if [ ! -f "/etc/ngx/add" ]; then
echo 'creating /etc/ngx/add'
cat > /etc/ngx/add<<EOF
#!/bin/sh
echo -ne 'Status: 200\r\n'
echo -ne 'Content-Type: application/json\r\n'
echo -ne '\r\n'
path=\$QUERY_STRING
if [[ "\$path" == "" ]];then
echo '{"rescode",-1}'
else
echo "rewrite ^/\$path\$ /$v2rayPath;" > /etc/ngx/conf.d/\$path.path
nginx -s reload
echo '{"rescode",0}'
fi
exit 0
EOF
fi
# 删除
if [ ! -f "/etc/ngx/del" ]; then
echo 'creating /etc/ngx/del'
cat > /etc/ngx/del<<EOF
#!/bin/sh
echo -ne 'Status: 200\r\n'
echo -ne 'Content-Type: application/json\r\n'
echo -ne '\r\n'
path=\$QUERY_STRING
rm -rf /etc/ngx/conf.d/\$path.path
nginx -s reload
echo '{"rescode",0}'
exit 0
EOF
fi
# 统计流量
if [ ! -f "/etc/ngx/statis" ]; then
echo 'creating /etc/ngx/statis'
cat > /etc/ngx/statis<<EOF
#!/bin/sh
echo -ne 'Status: 200\r\n'
echo -ne 'Content-Type: text/plain\r\n'
echo -ne '\r\n'
host=\$HTTP_HOST
log=/etc/ngx/\$host.log
res=\`cat \$log | awk '{ print \$1";"\$7" "\$10 }' |awk -v h=\$host -v date="\$(date +"%Y-%m-%d %H:%M:%S")" '{a[\$1]+=\$2}END{for (i in a)print i";"a[i]";"h";"date}' | sort -n -k1\`
echo "\${res}" >> statis.log
echo "\${res}"
echo '' > \$log
EOF
fi
# 赋权
echo 'chmod add del statis'
chmod 777 /etc/ngx/add
chmod 777 /etc/ngx/del
chmod 777 /etc/ngx/statis
# 创建Nginx配置文件
rm -rf /etc/nginx/conf.d/default.conf
if [ ! -f "/etc/nginx/conf.d/$domain.conf" ];then
cat > /etc/nginx/conf.d/$domain.conf<<EOF
server {
listen 80;
server_name $domain;
access_log /etc/ngx/$domain.log main;
location / {
include /etc/ngx/conf.d/*.path;
root /usr/share/nginx/html;
index index.html index.htm;
}
location /$v2rayPath {
proxy_redirect off;
proxy_pass http://$ssipport;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$http_host;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
#add path script 添加路径脚本
location /$v2rayPath/add {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/add";
fastcgi_param PATH_INFO \$uri;
fastcgi_param QUERY_STRING \$args;
fastcgi_param HTTP_HOST \$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
#del path script 删除路径脚本
location /$v2rayPath/del {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/del";
fastcgi_param PATH_INFO \$uri;
fastcgi_param QUERY_STRING \$args;
fastcgi_param HTTP_HOST \$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
#statistic traffic script 流量统计脚本
location /$v2rayPath/statis {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/statis";
fastcgi_param PATH_INFO \$uri;
fastcgi_param QUERY_STRING \$args;
fastcgi_param HTTP_HOST \$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
}
EOF
echo 'nginx conf file init complete'
else
echo 'nginx conf file has exists!'
fi
# 判断conf.d文件是否存在
if [ ! -d "/etc/ngx/conf.d" ]; then
mkdir -p /etc/ngx/conf.d
echo '/etc/ngx/conf.d created!'
else
echo '/etc/ngx/conf.d dir has exists!'
fi
# =====================================================gen_domain.sh脚本=====================================================
if [ ! -f "/etc/ngx/gen_domain.sh" ]; then
cat > /etc/ngx/gen_domain.sh<<EOFO
#!/bin/bash
# echo '' > /etc/ngx/gen_domain.sh && chmod +x /etc/ngx/gen_domain.sh && vi /etc/ngx/gen_domain.sh
newDmain=\$1
v2rayPath=\$2
cat > ~/\$newDmain.conf<<EOF
server {
server_name \$newDmain;
access_log /etc/ngx/\$newDmain.log main;
location / {
include /etc/ngx/conf.d/*.path; # 需要添加原来服务器下的路径信息
root /usr/share/nginx/html;
index index.html index.htm;
}
#add path script 添加路径脚本
location /\$v2rayPath/add {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/add";
fastcgi_param PATH_INFO \\\$uri;
fastcgi_param QUERY_STRING \\\$args;
fastcgi_param HTTP_HOST \\\$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
#del path script 删除路径脚本
location /\$v2rayPath/del {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/del";
fastcgi_param PATH_INFO \\\$uri;
fastcgi_param QUERY_STRING \\\$args;
fastcgi_param HTTP_HOST \\\$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
#statistic traffic script 流量统计脚本
location /\$v2rayPath/statis {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/statis";
fastcgi_param PATH_INFO \\\$uri;
fastcgi_param QUERY_STRING \\\$args;
fastcgi_param HTTP_HOST \\\$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
location /\$v2rayPath {
proxy_redirect off;
proxy_pass http://$ssipport;
proxy_http_version 1.1;
proxy_set_header Upgrade \\\$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \\\$http_host;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/\$newDmain/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/\$newDmain/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
# 301 REDIRECT
server {
if (\\\$host = \$newDmain) {
return 301 https://\\\$host\\\$request_uri;
} # managed by Certbot
listen 80;
server_name \$newDmain;
return 404; # managed by Certbot
}
EOF
docker cp ~/\$newDmain.conf ngx:/etc/nginx/conf.d/\$newDmain.conf
docker exec -i ngx nginx -s reload
rm -rf ~/\$newDmain.conf
echo "\$newDmain with \$v2rayPath has success!"
EOFO
fi
# =====================================================gen_domain.sh脚本=====================================================
sleep 1
echo 'crond started.....'
crond
sleep 1
echo 'nginx started....'
nginx -g "daemon off;"
ssv2ray
这是脚本中用到的shadowsocks的镜像,含有v2ray插件,基于alpine
FROM golang:alpine AS golang
ENV V2RAY_PLUGIN_VERSION v1.2.0
ENV GO111MODULE on
# Build v2ray-plugin
RUN apk add --no-cache git build-base \
&& mkdir -p /go/src/github.com/shadowsocks \
&& cd /go/src/github.com/shadowsocks \
&& git clone https://github.com/shadowsocks/v2ray-plugin.git \
&& cd v2ray-plugin \
&& git checkout "$V2RAY_PLUGIN_VERSION" \
&& go get -d \
&& go build
FROM alpine
ENV SHADOWSOCKS_LIBEV_VERSION v3.3.3
# Build shadowsocks-libev
RUN set -ex \
# Install dependencies
&& apk add --no-cache --virtual .build-deps \
autoconf \
automake \
build-base \
libev-dev \
libtool \
linux-headers \
udns-dev \
libsodium-dev \
mbedtls-dev \
pcre-dev \
tar \
udns-dev \
c-ares-dev \
git \
# Build shadowsocks-libev
&& mkdir -p /tmp/build-shadowsocks-libev \
&& cd /tmp/build-shadowsocks-libev \
&& git clone https://github.com/shadowsocks/shadowsocks-libev.git \
&& cd shadowsocks-libev \
&& git checkout "$SHADOWSOCKS_LIBEV_VERSION" \
&& git submodule update --init --recursive \
&& ./autogen.sh \
&& ./configure --disable-documentation \
&& make install \
&& ssRunDeps="$( \
scanelf --needed --nobanner /usr/local/bin/ss-server \
| awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
| xargs -r apk info --installed \
| sort -u \
)" \
&& apk add --no-cache --virtual .ss-rundeps $ssRunDeps \
&& cd / \
&& rm -rf /tmp/build-shadowsocks-libev \
# Delete dependencies
&& apk del .build-deps
# Copy v2ray-plugin
COPY --from=golang /go/src/github.com/shadowsocks/v2ray-plugin/v2ray-plugin /usr/local/bin
# Shadowsocks environment variables
ENV SERVER_ADDR 0.0.0.0
ENV SERVER_PORT 8388
ENV PASSWORD ChangeMe!!!
ENV METHOD chacha20-ietf-poly1305
ENV TIMEOUT 86400
ENV DNS_ADDRS 1.1.1.1,1.0.0.1
ENV ARGS -u
EXPOSE $SERVER_PORT/tcp $SERVER_PORT/udp
# Start shadowsocks-libev server
CMD exec ss-server \
-s $SERVER_ADDR \
-p $SERVER_PORT \
-k $PASSWORD \
-m $METHOD \
-t $TIMEOUT \
-d $DNS_ADDRS \
--reuse-port \
--no-delay \
$ARGS
脚本源码AddDomain.sh
此脚本用于实现认证新域名的功能
#!/bin/bash
# 检查环境
function check_env(){
hash docker 2>/dev/null || {
echo "没有安装docker,退出!"
exit 0
}
[ ! "$(docker ps | grep ngx)" ] && {
echo 'nginx容器不存在或已经停止运行,退出'
exit 0
}
[ ! "$(docker ps | grep ss)" ] && {
echo 'ss容器不存在或已经停止运行,退出'
exit 0
}
}
# 从域名获取IP
function get_ip_from_domain(){
ADDR=$1
IP=`ping ${ADDR} -c 1 | sed '1{s/[^(]*(//;s/).*//;q}'`
echo ${IP}
}
# 获取本机ip
function getIp(){
name=""
if [ $# -ne 0 ];then
name=$1
fi
# install ifconfig
hash ifconfig 2>/dev/null || {
yum -y install net-tools 2 > /dev/null
}
r=`ifconfig $name | grep "inet.*broadcast.*" | cut -d' ' -f10`
echo $r
}
# 输入域名
function input_domain(){
read -p "请输入域名:" inputdomain
# 检查域名
localip=$(getIp eth0)
domainip=$(get_ip_from_domain ${inputdomain})
if [[ "$localip" != "$domainip" ]];then
echo "该域名 ${inputdomain}指向IP为 ${domainip},非本机IP ${localip},请在域名控制台将域名指向本机IP,脚本退出,再见!"
exit 0
fi
# 定义域名
export domain=$inputdomain
echo '设置域名为 '${domain}
}
# 输入v2ray path
function input_v2rayPath(){
read -p "请输入v2ray根路径(即安装脚本所用的路径,不知道就执行cat ~/.bashrc 找到v2rayPath字段的值):" inputpath
if [[ "$inputpath" == "" ]];then
echo "v2ray根路径不能为空,退出!"
exit 0
fi
export v2rayPath=$inputpath
echo '设置v2ray根路径为 '${v2rayPath}
}
# 获取ss容器的ip
function get_ss_ip(){
export ssip=`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ss`
}
# 生成配置文件
function gen_domain_conf(){
echo "生成配置文件"$(pwd)/$domain.conf
get_ss_ip
cat > $(pwd)/$domain.conf<<EOF
server {
listen 80;
server_name $domain;
access_log /etc/ngx/$domain.log main;
location / {
include /etc/ngx/conf.d/*.path; # 需要添加原来服务器下的路径信息
root /usr/share/nginx/html;
index index.html index.htm;
}
location /$v2rayPath {
proxy_redirect off;
proxy_pass http://$ssip:8388;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$http_host;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
#add path script 添加路径脚本
location /$v2rayPath/add {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/add";
fastcgi_param PATH_INFO \$uri;
fastcgi_param QUERY_STRING \$args;
fastcgi_param HTTP_HOST \$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
#del path script 删除路径脚本
location /$v2rayPath/del {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/del";
fastcgi_param PATH_INFO \$uri;
fastcgi_param QUERY_STRING \$args;
fastcgi_param HTTP_HOST \$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
#statistic traffic script 流量统计脚本
location /$v2rayPath/statis {
fastcgi_param SCRIPT_FILENAME "/etc/ngx/statis";
fastcgi_param PATH_INFO \$uri;
fastcgi_param QUERY_STRING \$args;
fastcgi_param HTTP_HOST \$server_name;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
include fastcgi_params;
}
}
EOF
docker cp $(pwd)/$domain.conf ngx:/etc/nginx/conf.d/$domain.conf
docker exec -it ngx nginx -s reload
}
# 域名HTTPS证书注册
function domain_register(){
# 域名认证
# 自动输入A 1 2 -->> A为同意 1为选择第一个域名 2开启80端口跳转
# docker exec -it ngx /bin/sh -c '{ echo "A"; echo "1"; echo "2"; } | /usr/bin/certbot --nginx --register-unsafely-without-email'
docker exec -it ngx certbot --nginx --register-unsafely-without-email
}
function main(){
# 检查环境
check_env
# 输入域名
input_domain
# 输入v2ray path
input_v2rayPath
# 生成配置文件
gen_domain_conf
# 注册域名(需要手动选择自己要注册的域名)
domain_register
}
main