Skip to content

Instantly share code, notes, and snippets.

@lesonky
Last active March 16, 2020 06:13
Show Gist options
  • Save lesonky/c5bd4009ce0706b84f698d07122ffc25 to your computer and use it in GitHub Desktop.
Save lesonky/c5bd4009ce0706b84f698d07122ffc25 to your computer and use it in GitHub Desktop.
自建shadowscoks服务器及使用 #shadowsocks

这里使用DNSpod.cn的服务来实现DDns动态地址绑定

1. 添加dnspod_ddns.py文件

1.1 运行nano /usr/local/bin/dnspod_ddns.py

文件内容(注意需要修改main函数的params):

#!/usr/bin/env python3
# -*- coding:utf-8 -*-


import socket
import requests
import time
import logging

logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)


class DNSPod(object):
    """DNSPod ddns application."""

    def __init__(self, params):
        """Initialize with params."""
        self._params = params

    def run(self, params=None):
        if params is None:
            params = self._params
        public_ip = self.get_public_ip()
        # get record_id of sub_domain
        record_list = self.get_record_list(params)
        if record_list['code'] == '10':
            # create record for empty sub_domain
            record_id = self.create_record(params, public_ip)
            remote_ip = public_ip
        elif record_list['code'] == '1':
            # get record id
            record_id = record_list['record_id']
            remote_ip = record_list['ip_value']
        else:
            logger.error('!!!can not get record_id!!!')
            return -1
        params['record_id'] = record_id

        current_ip = remote_ip
        while True:
            try:
                public_ip = self.get_public_ip()
                if current_ip != public_ip:
                    logger.warning("update IP from %s to %s" % (current_ip, public_ip))
                    if self.ddns(params, public_ip):
                        current_ip = public_ip
                else:
                    logger.info("IP remains %s" % public_ip)
            except Exception as e:
                logger.error(e)
                pass
            time.sleep(300)

    def get_public_ip(self):
        """Get public ip via dnspod."""
        sock = socket.create_connection(('ns1.dnspod.net', 6666), timeout=30)
        ip = sock.recv(16)
        sock.close()
        return ip.decode('utf-8')

    def get_record_list(self, params):
        """Get record list.

        https://www.dnspod.cn/docs/records.html#record-list
        :return: dict of code, record_id and IP value
        """
        record_list_url = 'https://dnsapi.cn/Record.List'
        r = requests.post(record_list_url, data=params)
        code = r.json()['status']['code']
        record_id = r.json()['records'][0]['id'] if code == '1' else ""
        ip_value = r.json()['records'][0]['value'] if code == '1' else ""
        return dict(code=code, record_id=record_id, ip_value=ip_value)

    def create_record(self, params, ip):
        """Create record if not created before.

        https://www.dnspod.cn/docs/records.html#record-create
        :return: record_id of new record
        """
        params['value'] = ip
        record_create_url = 'https://dnsapi.cn/Record.Create'
        r = requests.post(record_create_url, data=params)
        logger.warning('create new record %s.%s with IP %s' % (params['sub_domain'], params['domain'], ip))
        assert r.json()['status']['code'] == '1'
        record_id = r.json()['record']['id']
        return record_id

    def ddns(self, params, ip):
        """Update ddns ip.

        https://www.dnspod.cn/docs/records.html#dns
        """
        params['value'] = ip
        ddns_url = 'https://dnsapi.cn/Record.Ddns'
        r = requests.post(ddns_url, data=params)
        logger.info('status: %s, reason: %s' % (r.status_code, r.reason))
        return r.json()['status']['code'] == '1'


def main():
    # initialize params
    # Use Token, check https://support.dnspod.cn/Kb/showarticle/tsid/227
    ID = '83429'  # replace with your ID
    Token = 'e7992492901c9c2ad0724c7aa9008517'  # replace with your Token
    params = dict(
        login_token=("%s,%s" % (ID, Token)),
        format='json',
        domain='XXXX.com',  # replace with your domain
        sub_domain='XXXX',  # replace with your sub_domain
        record_type='A',
        record_line='默认'
    )

    dnspod = DNSPod(params)
    dnspod.run()


if __name__ == "__main__":
    main()

1.2 运行chmod +x /usr/local/bin/dnspod_ddns.py修改文件权限

2. 添加文件'dnspod-ddns.service'

2.1 运行nano /etc/systemd/system/dnspod-ddns.service

文件内容:

[Unit]
Description=DNSPod DDNS Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/dnspod_ddns.py
KillSignal=SIGINT
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

3.启动服务

3.1 设置开机启动

运行:systemctl enable dnspod-ddns.service

3.2 启动脚本

运行:4systemctl start dnspod-ddns.service

网址

这个服务现在是腾讯云的,如果是阿里云买的域名,需要去阿里云设置dns服务器地址

  1. 扫码登录
  2. 添加域名解析
  3. 阿里云买的域名,需要去阿里云设置dns服务器地址为 f1g1ns1.dnspod.netf1g1ns2.dnspod.net
  4. 进入 用户中心=>安全设置 选 API Token 新建一个Token 注意保存,这个token只显示一次
  5. 使用的时候 token 的 ID 作为用户名,token作为密码

这个服务可以用在很多地方,例如家里的NAS系统等

服务器端

步骤

  1. 按照上面的步骤,安装ss服务
  2. 一件脚本安装 v2ray bash <(curl -L -s https://install.direct/go.sh)
  3. 利用配置在线生成器生成一个配置文件
  4. 修改原有配置文件 /etc/v2ray/config.json
  5. 启动服务 service v2ray start
  6. 查看状态 service v2ray status

参考

客户端使用

macos

  1. 下载V2rayU
  2. 按照ss客户端的配置配一下服务器,然后就可以使用了

windows

  1. 下载v2rayN
  2. 按照ss客户端配置一下服务器

mac

  • 安装obfs brew install simple-obfs
  • 下载最新的shadowsocks客户端
  • 配置自己的服务器
  • 服务器插件填obfs-local
  • 插件参数填obfs=http;obfs-host=www.bing.com

win

android

ios (切换账号区域,购买客户端 shadowproxy)

  • 配置相同
  • 设置混淆plain
  • 混淆参数www.bing.com

根据目前还幸存的大流量协议应该是WebSocket+TLS这种

  1. v2ray
bash <(curl -L -s https://install.direct/go.sh)

nano /etc/v2ray/config.json

具体配置不细说,只是复制一份,注意uuid自己生成,注意"path": "/ray"要自己改一下,这是为了安全,网上公开的默认参数等于让别人直接检测到装了v2ray

{
  "inbounds": [
    {
      "port": 10000,
      "listen":"127.0.0.1",//只监听 127.0.0.1,避免除本机外的机器探测到开放了 10000 端口
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
            "alterId": 64
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "wsSettings": {
        "path": "/ray"
        }
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

改完配置重启下v2ray

systemctl start v2ray

  1. 现在开始把 服务器上在127.0.0.1:10000上的v2ray通过caddy暴露到公网上去

2.1 安装caddy

wget -qO- https://getcaddy.com | bash -s personal
setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy

2.2 配置caddy运行环境

sudo apt-get install apache2 && sudo apt-get remove apache2

sudo mkdir /etc/caddy
sudo chown -R root:root /etc/caddy
sudo mkdir /etc/ssl/caddy
sudo chown -R root:www-data /etc/ssl/caddy
sudo chmod 0770 /etc/ssl/caddy

sudo mkdir /var/www
sudo chown www-data:www-data /var/www
sudo chmod 555 /var/www

sudo mkdir /var/www/webeye.baidu.com
sudo chown -R www-data:www-data /var/www/webeye.baidu.com
sudo chmod -R 555 /var/www/webeye.baidu.com

nano /etc/caddy/Caddyfile
# 注意两点 这里假设域名是 webeye.baidu.com,路劲是 /ray 这个是上面v2ray里面的那个,不要用这个网上到处写的ray
# 而www.baidu.com 这是个真的网址,最好是某个看起来很和谐的网站,caddy配置好后浏览器打开webeye.baidu.com会看到百度
# 特别提示,不要以为这里改成谷歌,打开webeye.baidu.com就能访问谷歌,ip会被很快封掉
webeye.baidu.com:443 {
  root /var/www/webeye.baidu.com
  gzip
#  tls /root/caddy/caddy.crt /root/caddy/caddy.key
#  log /root/caddy/caddy.log
  proxy / https://www.baidu.com
  proxy /ray 127.0.0.1:9000 {
    websocket
    header_upstream -Origin
  }
}


nano /etc/systemd/system/caddy.service
开始,不包括本行
[Unit]
Description=Caddy HTTP/2 web server
Documentation=https://caddyserver.com/docs
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service

; Do not allow the process to be restarted in a tight loop. If the
; process fails to start, something critical needs to be fixed.
StartLimitIntervalSec=14400
StartLimitBurst=10

[Service]
Restart=on-abnormal

; User and group the process will run as.
User=www-data
Group=www-data

; Letsencrypt-issued certificates will be written to this directory.
Environment=CADDYPATH=/etc/ssl/caddy

; Always set "-root" to something safe in case it gets forgotten in the Caddyfile.
ExecStart=/usr/local/bin/caddy -log stdout -log-timestamps=false -agree=true -conf=/etc/caddy/Caddyfile -root=/var/tmp
ExecReload=/bin/kill -USR1 $MAINPID

; Use graceful shutdown with a reasonable timeout
KillMode=mixed
KillSignal=SIGQUIT
TimeoutStopSec=5s

; Limit the number of file descriptors; see `man systemd.exec` for more limit settings.
LimitNOFILE=1048576
; Unmodified caddy is not expected to use more than that.
LimitNPROC=512

; Use private /tmp and /var/tmp, which are discarded after caddy stops.
PrivateTmp=true
; Use a minimal /dev (May bring additional security if switched to 'true', but it may not work on Raspberry Pi's or other devices, so it has been disabled in this dist.)
PrivateDevices=false
; Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
ProtectHome=true
; Make /usr, /boot, /etc and possibly some more folders read-only.
ProtectSystem=full
; … except /etc/ssl/caddy, because we want Letsencrypt-certificates there.
;   This merely retains r/w access rights, it does not add any new. Must still be writable on the host!
ReadWritePaths=/etc/ssl/caddy
ReadWriteDirectories=/etc/ssl/caddy

; The following additional security directives only work with systemd v229 or later.
; They further restrict privileges that can be gained by caddy. Uncomment if you like.
; Note that you may have to add capabilities required by any plugins in use.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

结束,不包括本行


sudo systemctl daemon-reload
sudo systemctl start caddy.service
sudo systemctl enable caddy.service
  1. 客户配置

注意三处 webeye.baidu.com 和 id 以及 "path": "/ray"

{
  "inbounds": [
    {
      "port": 1080,
      "listen": "127.0.0.1",
      "protocol": "socks",
      "sniffing": {
        "enabled": true,
        "destOverride": ["http", "tls"]
      },
      "settings": {
        "auth": "noauth",
        "udp": false
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "vmess",
      "settings": {
        "vnext": [
          {
            "address": "webeye.baidu.com",
            "port": 443,
            "users": [
              {
                "id": "b831381d-6324-4d53-ad4f-8cda48b30811",
                "alterId": 64
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "wsSettings": {
          "path": "/ray"
        }
      }
    }
  ]
}

以下安装使用的环境是Ubuntu 18.04,编辑文件的命令nano 可以换成 vim

1 升级到最新版本

apt update && apt -y dist-upgrade

2 开启bbr

2.1 编辑文件:/etc/sysctl.conf

命令: nano /etc/sysctl.conf

将下面的内容加入文件:

net.ipv4.neigh.default.base_reachable_time_ms = 600000
net.ipv4.neigh.default.mcast_solicit = 20
net.ipv4.neigh.default.retrans_time_ms = 250
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr

kernel.sysrq=0
kernel.core_uses_pid=1
net.ipv4.tcp_syncookies=1
kernel.msgmnb=65536
kernel.msgmax=65536
kernel.shmmax=68719476736
kernel.shmall=4294967296
net.ipv4.conf.all.accept_source_route=0
net.ipv4.conf.default.accept_source_route=0
net.ipv4.conf.all.log_martians=1
net.ipv4.conf.default.log_martians=1
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.default.accept_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.icmp_echo_ignore_broadcasts=1
net.ipv4.icmp_ignore_bogus_error_responses=1
net.ipv4.conf.all.secure_redirects=0
net.ipv4.conf.default.secure_redirects=0
kernel.randomize_va_space=1
net.core.wmem_max=12582912
net.core.rmem_max=12582912
fs.suid_dumpable=0
fs.protected_hardlinks=1
fs.protected_symlinks=1
net.ipv4.ip_forward=1
# net.ipv4.tcp_fastopen=3

2.2 使该命令生效: sysctl -p 或者reboot重启

2.3 检测是否启用了bbr

sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control

两条命令的结果都出现bbr即为正常

3 安装shadowsocks

sudo apt update
sudo apt install shadowsocks-libev

4 安装obfs

4.1 参考:simple-obfs

4.1.1 安装编译环境

先安装编译用的工具(Debian / Ubuntu)

sudo apt-get install --no-install-recommends build-essential autoconf libtool libssl-dev libpcre3-dev libev-dev asciidoc xmlto automake

然后拖源码编译

git clone https://github.com/shadowsocks/simple-obfs.git
cd simple-obfs
git submodule update --init --recursive
./autogen.sh
./configure && make
sudo make install

5 配置

5.1 编辑文件:/etc/shadowsocks-libev/config.json

命令: nano /etc/shadowsocks-libev/config.json 将下面的内容加入文件: 注意,这里需要修改成自己的参数配置

{
    "server":"0.0.0.0",
    "server_port":8080,
    "local_port":1080,
    "password":"9Sm5rpDh5F",
    "timeout":600,
    "method":"chacha20-ietf-poly1305",
    "plugin":"obfs-server",
    "plugin_opts":"obfs=http"
}

6 重启ss

systemctl restart shadowsocks-libev
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment