Here I use Shadowsocks-libev for better performance

Shadowsocks-libev

Shadowsocks-libev is written in pure C and depends on libev.

# install
sudo apt install shadowsocks-libev
sudo ufw allow 8389

# config
sudo tee /etc/shadowsocks-libev/config.json > /dev/null<<EOF
{
 "server":"0.0.0.0",
 "server_port":8389,
 "local_port":1081,
 "password":"$(openssl rand -base64 12)",
 "timeout":60,
 "method":"chacha20-ietf-poly1305"
}
EOF     

# start
sudo systemctl restart shadowsocks-libev
sudo systemctl start shadowsocks-libev.service
sudo systemctl enable shadowsocks-libev.service

# check
sudo systemctl status shadowsocks-libev.service

Problem

systemctl status shadowsocks-libev.service status shows following error:[2]

This system doesn’t provide enough entropy to quickly generate high-quality random numbers. The service will not start until enough entropy has been collected.

Solution

sudo apt-get install rng-tools
sudo rngd -r /dev/urandom

fail2ban

There are also other options to secure the Shadowsocks Server[3]

But since my server is only uesd by some acquaintances, I just care about brute force password cracking.

Intro

fail2ban is used to ban IP addresses conducting too many failed login attempts.

How fail2ban works?[4] fail2ban use date pattern to capture and remove the date from log, and then use failregex to parse the log to get the IP. After that, fail2ban would update the firewall rule to block the IP addresses

log file

Both Shadowsocks and Shadowsocks-libev output log to /var/log/syslog, Shadowsocks also output some INFO and DEBUG level log to /var/log/shadowsocks.log

Shadowsocks can customize log file location but Shadowsocks-libev cannot[5]

I would use ufw rather than iptables to modify my firewall sudo vim /etc/fail2ban/jail.local

[DEFAULT]
banaction = ufw

Shadowsocks-libev

log sample

Aug 15 08:59:07 <hostname> ss-server[1382]: 2018-08-15 08:59:07 ERROR: failed to handshake with <HOST>: authentication error

create filter

sudo tee /etc/fail2ban/filter.d/shadowsocks-libev.conf > /dev/null <<EOF
[INCLUDES]
before = common.conf

[Definition]
_daemon = ss-server

failregex = ^\w+\s+\d+ \d+:\d+:\d+\s+%(__prefix_line)sERROR:\s+failed to handshake with <HOST>: authentication error$

ignoreregex =

datepattern = %%Y-%%m-%%d %%H:%%M:%%S
EOF
sudo vim /etc/fail2ban/jail.local

test fail2ban-regex /var/log/syslog /etc/fail2ban/filter.d/shadowsocks-libev.conf --print-all-matched

update jail config

sudo vim /etc/fail2ban/jail.local
[shadowsocks-libev]
enabled = true
filter = shadowsocks-libev
port = 8839
logpath = /var/log/syslog

maxretry = 3
findtime = 3600
bantime = 3600

start fail2ban

sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo systemctl status fail2ban
sudo fail2ban-client status shadowsocks
sudo fail2ban-client status shadowsocks-libev

Notes

  • use ufw rather than iptables to modify firewall, it would make life easier

UFW (Uncomplicated Firewall) is a front-end for iptables and is particularly well-suited for host-based firewalls.https://help.ubuntu.com/community/Firewall

  • Can't assign requested address[11] In config file, set the server_ip as 0.0.0.0

Reference

[1] https://novnan.github.io/Shadowsocks/setup-Shadowsocks-on-ubuntu-1604/ [2] https://www.linuxbabe.com/ubuntu/shadowsocks-libev-proxy-server-ubuntu-16-04-17-10 [3] https://github.com/shadowsocks/shadowsocks/wiki/Securing-Public-Shadowsocks-Server [4] https://github.com/fail2ban/fail2ban/issues/2201#issuecomment-413155557 [5] https://github.com/shadowsocks/shadowsocks/issues/1242 [6] https://fail2ban.readthedocs.io/en/latest/filters.html [7] https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters [8] https://github.com/coleturner/fail2ban-slack-action [9] https://api.slack.com/methods/chat.postMessage [10] https://api.slack.com/incoming-webhooks [11] https://github.com/shadowsocks/shadowsocks/issues/961