SSR快速搭建手册

系统:centos、archlinux 平台:搬瓦工、conoha User:root 搬瓦工 centos C-P 流程(copy-past+回车即可)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

yum install epel-release
yum install python-setuptools && easy_install pip
yum install m2crypto git libsodium nano
pip install cymysql

git clone -b manyuser https://github.com/shadowsocksr/shadowsocksr

nano /etc/shadowsocks.json


{
"server":"0.0.0.0",
"server_ipv6": "::",
"local_address":"127.0.0.1",
"local_port":1080,
"port_password":{
"1234":"password1",
"5678":"password2"
},
"timeout":300,
"method":"aes-256-cfb",
"fast_open": false
}



nano /etc/init.d/shadowsocks




#!/bin/sh
#chkconfig: 2345 85 15
#description: some desc here
#processname: the_process_name
case "$1" in
start)
nohup python /root/shadowsocks/shadowsocks/server.py -c /etc/shadowsocks.json;;
stop)
;;
restart)
;;
*)
echo "Usage: #0 {start|stop|restart}";;
esac




chmod +x /etc/init.d/shadowsocks



chkconfig --add shadowsocks

chkconfig shadowsocks on

conoha archlinux C-P 流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

pacman -S python-setuptools python-pip python2-m2crypto git libsodium


pip install cymysql


git clone -b akkariiin/master https://github.com/shadowsocksrr/shadowsocksr


nano /etc/shadowsocks.json


{
"server":"0.0.0.0",
"server_ipv6": "::",
"local_address":"127.0.0.1",
"local_port":1080,
"port_password":{
"1234":"password1",
"5678":"password2"
},
"timeout":300,
"method":"aes-256-cfb",
"fast_open": false
}


mv shadowsocksr/ /usr/bin/shadowsocksr/



nano /etc/systemd/system/shadowsocksR.service



[Unit]
Description=ShadowsocksR Server Service
Requires=network.target
After=network.target

[Service]
Type=simple
User=nobody
Restart=always
# way 1
AmbientCapabilities=CAP_NET_BIND_SERVICE
# way 2
#PermissionsStartOnly=true
#ExecStartPre=-/bin/setcap 'cap_net_bind_service=+eip' /bin/python2.7
#ExecStartPre=-/bin/setcap 'cap_net_bind_service=+eip' /bin/python3.6
#ExecStartPre=-/bin/setcap 'cap_net_bind_service=+eip' /bin/python3.7
#ExecStartPre=-/usr/sbin/setcap 'cap_net_bind_service=+eip' /bin/python2.7
#ExecStartPre=-/usr/sbin/setcap 'cap_net_bind_service=+eip' /bin/python3.6
#ExecStartPre=-/usr/sbin/setcap 'cap_net_bind_service=+eip' /bin/python3.7
ExecStart=/usr/bin/python /usr/bin/shadowsocksr/shadowsocks/server.py -c /etc/shadowsocks.json

[Install]
WantedBy=multi-user.target



systemctl start shadowsocksR.service

systemctl status shadowsocksR.service

systemctl enable shadowsocksR.service

archlinux修改服务配置文件后需要重载并重启服务才能有效

1
systemctl daemon-reload

P: archlinux默认的python是python3,SSR的开发是针对python2的,所以在作者收到bug反馈并修复之前会有各种奇怪bug,所以需要指定archlinux使用python2
P2: 上述的systemd配置文件中ExecStartPre部分和PermissionsStartOnly=true配合,完成在服务启动前以root权限赋予监听特权端口(0~1024)的能力,且在/bin/setcap前添加-号忽略执行失败,以完成无需服务本身使用root即可监听80及443端口的能力。 详见: https://bugzilla.redhat.com/show_bug.cgi?id=651797 https://unix.stackexchange.com/questions/207469/systemd-permission-issue-with-mkdir-execstartpre

1
journalctl -xeu shadowsocksR

可以查看系统服务日志 授权可执行文件绑定特权端口

1
setcap 'cap_net_bind_service=+eip' /bin/python2.7

系统更新后使用的脚本

1
2
3
4
5
6
7
8
9
nano after-update.sh

setcap 'cap_net_bind_service=+eip' /bin/python2.7
setcap 'cap_net_bind_service=+eip' /bin/python3.6
setcap 'cap_net_bind_service=+eip' /bin/python3.7

chmod +x after-update.sh
./after-update.sh

centos手动创建服务

参见:
http://www.cnblogs.com/sheldonxu/archive/2012/04/13/2445399.html
http://www.centoscn.com/CentOS/config/2014/0804/3424.html

1. 在/etc/init.d下创建Service启动脚本

脚本头部的固定写法:

1
2
3
4
#!/bin/sh
#chkconfig: 2345 85 15
#description: some desc here
#processname: the_process_name

其中2345是runlevel,即2-5,85是系统启动顺序,15是系统关闭顺序
当然,它要有运行权限: chmod +x /etc/init.d/some_service

脚本内容的一般写法

1
2
3
4
5
6
7
8
9
10
11
case "$1" in
start)
echo "Starting myservice...";;
stop)
echo "Shutting down myservice...";;
restart)
echo "Shutting down myservice..."
echo "Starting myservice...";;
*)
echo "Usage: #0 {start|stop|restart}";;
esac

2. 注册到系统

1
chkconfig --add some_service

3. 设置随系统启动 激活:

1
chkconfig some_service on

取消:

1
chkconfig some_service off

linux使指定程序在任意用户执行时均拥有root权限

在编程使用raspberry的GPIO口时 要想操作GPIO、I2C必须要拥有root权限 但是在多应用程序通信联合运行时就出现一个大问题 非root应用程序不能启动一个访问gpio口的应用程序 想到的解决方法一个就是以root启动调用者 但是这样就失去了安全性 第二个就是使得被调用程序始终以root权限执行 操作方法如下 1、将可执行文件的所有者设置为root 2、设置所有人可读可执行此文件(这两步直接在root下gcc编译即可实现)3、使用“chmod u+s xxx”将xxx文件设置为s权限 这样这个程序在使用ls -all查看时便是如此权限“-rwsr-xr-x” 然后就可以让任意用户使用普通的调用方法却能让程序运行在root权限下   参考:http://jazka.blog.51cto.com/809003/240549

Archlinux更新时导入Key出错解决方案

pacman -Syu 系统更新时,在下载完新的包之后出现如下错误

(20/20) checking keys in keyring                   [----------------------] 100%
downloading required keys...
error: key "A6234074498E9CEE" could not be looked up remotely
error: required key missing from keyring
error: failed to commit transaction (unexpected error)
Errors occurred, no packages were upgraded.

显示为无法导入Key

wiki中的说明如下 链接

Outdated archlinux-keyring package.
Incorrect date.
Your ISP blocked the port used to import PGP keys.
Your pacman cache contains copy of unsigned packages from previous attempts.

其实首先尝试手动更新key

1
pacman-key --populate archlinux

异常基本可以解决

否则就是服务器无法访问或者keyring包版本太老需要更新

Erlang在OTP框架下的代码热更新

网上有许多说原理的,但是却找不到一个完整的在OTP框架下的有关code_change函数用法的热更新

内容参考自以下网站与OTP文档
http://www.jiancool.com/article/61163151807/

实践了一下,关键的更新代码是这样

1
2
3
4
5
6
update() ->
sys:suspend(?SERVER),
code:purge(?MODULE),
code:load_file(?MODULE),
sys:change_code(?SERVER, ?MODULE, undefined, extraData),
sys:resume(?SERVER).

首先suspend暂停线程(change_code必须在暂停状态下使用。并且,暂停状态下线程不会响应call与cast,只会响应带外消息【所以主动模式TCP/UDP通信模块没法直接更新?】)
purge清除旧的模块代码(可选,但是如果不清除旧代码,在第二次更新是会出现not_purged错误并且更新失败)(其实是清除上一次更新后遗留下来的代码)(也可使用soft_purge进行软清除)
load_file加载新的代码文件
change_code调用对应进程的对应旧模块的新版本code_change回调函数来做一些转换操作(这里一般进行state状态量从旧版本到新版本的转换操作)(P:调用的是新代码的code_change函数,所以只要每次更新时在新代码中放置从旧代码到新代码的对state变量的转换函数即可)(网上就没有说清楚这个地方的)
最后调用resume恢复进程运行

树莓派Archlinux安装X11桌面环境

部分参照:http://www.tommyappco.com/additions.php?req=28 BUT:我用的是Pi2 arm7版本 使用上面连接中的gdm桌面时表示慢到无法使用 而且NetworkManager和netctl好像不兼容,不能同时生效 下面是安装桌面环境的代码

pacman -Syu pacman -S xf86-video-fbdev xorg-xinit dbus pacman -S xorg-server xorg-utils xorg-server-utils mesa pacman -S xorg-twm xterm xorg-xclock pacman -S xfce4

之后可以使用startxfce4启动桌面看一看 使用logout退出桌面并查看错误输出 之后如需启动桌面环境直接执行如下指令即可

startxfce4

archlinux安装VNC服务器

完全参照:https://wiki.archlinux.org/index.php/Virtual\_Network\_Computing_%28%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%29

安装tigervnc

这是一个TightVNC的linux实现
以你需要的用户身份执行vncserver第一次启动、设置密码并测试服务器
默认的是第一个桌面:1
实际端口是5900+1

如下指令可以关闭某个桌面

1
vncserver -kill :1

可以编辑~/.vnc/xstartup文件来设置vnc使用的桌面环境
此文件功能类似于.xinitrc
可参照xinitrc来编辑

hit: 简单的编辑方法是
注掉所有exec开头的行
并且注掉末尾最后一个exec行前面的连续几行(这几行末尾有&,是和exec同时执行的内容)
可添加如下指令在文件末尾启动桌面环境
exec startxfce4

windows下使用TightVNC连接即可

设置开关机行为
示例文件在 /usr/lib/systemd/system/vncserver.service

1
cp /usr/lib/systemd/system/vncserver.service /etc/systemd/system/vncserver@:1.service

然后编辑/etc/systemd/system/vncserver@:1.service
可以看到其中有使用说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# The vncserver service unit file 
#
# 1. Copy this file to /etc/systemd/system/vncserver@:x.service
# Note that x is the port number on which the vncserver will run. The default is 1 which
# corresponds to port 5901. For a 2nd instance, use x=2 which corresponds to port 5902.
# 2. Edit User=
# ("User=foo")
# 3. Edit and vncserver parameters appropriately
# ("/usr/bin/vncserver %i -arg1 -arg2 -argn")
# 4. Run \`systemctl --system daemon-reload\`
# 5. Run \`systemctl enable vncserver@:<display>.service\`
#
# DO NOT RUN THIS SERVICE if your local area network is untrusted!
#
# See the wiki page for more on security
# https://wiki.archlinux.org/index.php/Vncserver

其实我们只需要在User=后面添加我们的用户名即可
如果有需要的话可以修改ExecStart这一项添加启动参数的方式改变行为
之后重载systemctl

1
systemctl --system daemon-reload

再启动服务

1
systemctl enable vncserver@:<display>.service

即可使用

在使用时可以发现VNC不会自动根据客户机改变桌面分辨率
所以我们可以在启动参数中设置一个分辨率

比如wiki上的示例

Vncserver 通过开关(命令行参数)来提供灵活性。下面的例子启动具有特定分辨率、允许多用户同时观看/控制且设置 dpi 为 96 的 VNC 服务。
$ vncserver -geometry 1440x900 -alwaysshared -dpi 96 :1

如需要完整的选项表,向 vncserver 传递 -help 开关。

1
vncserver -help

archlinux arm 树莓派设置网络连接与无线网络连接

到手两个树莓派
其中一个装了arch
但是因为家里网络环境只有无线网络
arch默认的无线却没有wpa加密的支持包
于是便有了此文
下面是整理的内容

相关工具命令:

1
2
3
4
5
6
7
8
9

查看网络设备
**ip
link**
查看网络地址
**ifconfig**
查看系统服务状态
**systemctl**

使用netctl工具的手动网络配置方法
来自:https://raspberrypi.stackexchange.com/questions/7987/wifi-configuration-on-arch-linux-arm

在/etc/netctl/examples/目录下有netctl网络连接工具配置文件的范例
从范例创建一个新的网络连接配置(以普通的wpa加密的无线网络连接为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
从wireless-wpa范例文件创建一个权限为640的配置文件 
这样的权限配置可以防止配置文件中的密码泄露

install -m640 /etc/netctl/examples/wireless-wpa /etc/netctl/wireless-home

编辑这个文件
将其中的MyNetwork和WirelessKey替换为SSID和密码
保存文件
启动配置文件

netctl start wireless-home

启动后可以ping一下进行检测
没问题之后设置该配置文件开机自启动

netctl enable wireless-home

其实netctl操作的是systemctl服务中的netctl服务
启动配置文件时真正做的事情是以配置文件启动服务
netctl start xxx

相当于
systemctl start netctl@xxx

所以当出现问题时会显示要求使用如下命令查看故障原因
systemctl status netctl@xxx

然后.如果在上面启动配置文件时遇到错误
查看服务的status时发现如下信息就可以做对应的解决方案
如果说wpa-s…什么什么的一个东西没有安装
是因为你使用的是wpa加密的无线网络
但是没有安装那个支持wpa的库
需要安装后再试
如果说这个配置文件“already up”
说明对应的设备端口已经在使用中
使用如下命令停用该设备再启用配置文件即可
ip link set 设备名(比如eth0) down
参见:https://wiki.archlinux.org/index.php/Netctl#Troubleshooting
https://wiki.archlinux.org/index.php/Network\_configuration


另:如果使用有线网络的DHCP自动分配
插上网线再启动dhcpcd服务即可
另外:在配置静态IP是会遇到如下格式的IP
192.168.1.21/24
这是CIDR表示法,把ip地址和子网掩码合并到一起,可以一个ip表示一个ip簇
参见https://en.wikipedia.org/wiki/Classless\_Inter-Domain\_Routing#CIDR\_notation

常用的255.255.255.0等价于24

Erlang分布式环境下注册名与调用方法

在分布式环境下进行远程调用

标准的OTP模型是使用global参数注册server名,使用global参数进行调用
global注册时会将信息注册到kernel.global模块中.global模块会在分布式系统运行时运行

参见

1
kernel-3.2/doc/html/global.htmlstdlib-2.4/doc/html/gen_server.html#start\_link-3 stdlib-2.4/doc/html/gen_server.html#cast-2

同样的,在gen_server文档中的一个细节是
如果start_link注册是使用的是global模式,在cast、call等调用时也要使用该模式才能正确调用
另:在不同节点上的代码要直接访问的部分一定要在调用节点本地有代码被加载,否则无法正确调用运行

下面的内容来自:https://veniceweb.googlecode.com/svn/trunk/public/daily_tech_doc/erlang_global_20091109.txt


重点介绍erlang的global模块.

  1. 介绍:
    这个全局服务是通过一个global_name_server的process来提供的,这个进程存在于每一个erlang node, 这个全局名字服务在每个节点启动的时候自动启动.

这个模块在所有的链接的erlang节点的集群中实现了register_name/2和whereis_name/1的功能.一个注册名是一个pid的别名,
这个名字服务进程管理这些注册的pid,如果一个process终止,名字将自动被注销unregistered.

这些注册名储存在name table中,这个name table在每一个节点上都存在,因此名字服务的调用是快速的,当一个操作改变了name table, 所有的节点的name table都会自动被更新.

  1. 单个节点的例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    -module(test).
    -export([start/1, rpc_call/2, handle_msg/1]).

    start(Name) ->
    Pid = spawn(?MODULE, handle_msg, [Name]),
    register(Name, Pid). %% 在本地node注册process的名字

    rpc_call(Name, Msg) ->
    Name ! {Msg, self()}, %% 向本地node的process发消息
    receive
    {Reply, Name} ->
    Reply
    end.

    handle_msg(Name) ->
    receive
    {stop, Pid} ->
    Pid ! {stop, Name};
    {Msg, Pid} ->
    Pid ! {“received your msg: ” ++ Msg, Name},
    handle_msg(Name)
    end.

测试:
启动一个本地的process, 并注册一个名字pid1, 调用whereis/1测试,返回Pid,
测试通过名字pid1对进程发消息,
之后停止process, 再次调用whereis/1测试,返回undefined

1
2
3
4
5
6
7
8
9
10
11
12
> test:start(pid1).
true
> whereis(pid1).
<0.64.0>
> test:rpc_call(pid1, “test – 1”).
“received your msg: test – 1”
> test:rpc_call(pid1, “test – 2”).
“received your msg: test – 2”
> test:rpc_call(pid1, stop).
stop
> whereis(pid1).
undefined
  1. Erlang Nodes集群的例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    -module(test).
    -export([start/2, rpc_call/2, handle_msg/1]).

    start(Name, Node) ->
    Pid = spawn(Node, ?MODULE, handle_msg, [Name]),
    global:register_name(Name, Pid). %% 注册global的process的名字

    rpc_call(Name, Msg) ->
    global:send(Name, {Msg, self()}), %% 向global的name消息发送方式
    receive
    {Reply, Name} ->
    Reply
    end.

    handle_msg(Name) ->
    receive
    {stop, Pid} ->
    Pid ! {stop, Name};
    {Msg, Pid} ->
    Pid ! {“received your msg: ” ++ Msg, Name},
    handle_msg(Name)
    end.

测试:
在同一台机器上启动三个节点的erlang集群:

script
1
2
3
erl -sname node1 -setcookie testcookie
erl -sname node2 -setcookie testcookie
erl -sname node3 -setcookie testcookie

在node1上启动服务:

1
2
3
4
5
6
7
8
9
10
(node1@dev-pc)> test:start(pid1, node()).
yes
(node1@dev-pc)> test:rpc_call(pid1, “msg – 1”).
“received your msg: msg – 1”
在node2和node3上测试效果:
(node3@dev-pc)> test:rpc_call(pid1, “msg – 3”).
“received your msg: msg – 3”

(node2@dev-pc)> test:rpc_call(pid1, “msg – 2”).
“received your msg: msg – 2”
  1. 分布式的知识补充:
    <1> 如何在调用远程node上的方法?
    1
    rpc:call(Node, Mod, Func, [Arg1, … ArgN]).
    会在Node上进行一次Mod:Func(Arg1, … ArgN)调用.

节点名的形式是: NodeName@Host, NodeName和Host都是atom(), 其实整个节点名就是一个atom().

<2> 在不需要DNS的情况下使用erl -sname node1, 需要DNS的情况下使用erl -name node2

<3> 设置cookie:

script
1
erl -setcookie testcookie

或者erlang:set_cookie(Node, testcookie)

<4> 如何保持两个node上的代码版本一致?
可以使用nl(Mod), 这个操作会使所有互联的节点上加载Mod.

<5> 判断节点的连通性: net_adm:ping(Node)

<6> node() -> Node 返回本地节点的名字
nodes() -> [Node] 返回网络上与当前节点连接的所有其它节点列表

SS客户端支持负载均衡与服务器优选

最新版Shadowsocks-win-2.5.1已经支持多服务器负载均衡与优选功能了
在选择服务器的菜单中已经有了“负载均衡”和“高可用”的选项了
再也不会因为视频大流量导致TCP链接被临时阻断了
看视频时使用负载均衡能够使得YTB视频加载更快
浏览网页时使用高可用提高网页加载速度..

看了一下Git上该项目的说明,可以自己实现IStrategy类改进负载均衡的算法。
而看了一下当前默认的负载均衡算法,TCP部分使用的是随机分配算法,UDP部分使用的是标准的求余分布. 下面是负载均衡部分的服务器分布代码
2015-07-31 20_12_32-shadowsocks-csharp - Microsoft Visual Studio(管理员)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Server GetAServer(IStrategyCallerType type, IPEndPoint localIPEndPoint)
{
    var configs = _controller.GetCurrentConfiguration().configs;
    int index;
    if (type == IStrategyCallerType.TCP)
    {
        index = _random.Next();
    }
    else
    {
        index = localIPEndPoint.GetHashCode();
    }
    return configs[index % configs.Count];
}

我感觉负载均衡算法如果能够再加入可用性测试的部分就更好.
像我这种有五六个服务器的使用这个样的会更好….