Compile shadowsocks-libev statically
(Update 2021-01-01: this article has been revised to adopt latest ss-libev)
Previously I’ve discussed how to compile and run an user-mode Linux.
In this post, I’ll talk about how to compile a statically-linked shadowsocks-libev.
Preparation
Before we do anything, we need to install basic build packages.
Following are common package group you may use:
CentOS/Fedora:
sudo yum groupinstall "Development Tools"Debian/Ubuntu:
sudo apt-get install build-essentialArch Linux/Manjaro:
sudo pacman -Sy base-devel
You may happen to install git, autoconf, automake, libtool, gettext, asciidoc, xmlto manually.
To compile shadowsocks-libev(ss-libev for short) statically, its dependencies must be compiled(also static) first.
ss-libev depends on several packages: mbedTLS, libsodium, pcre, libev, c-ares.
And assuming current directory is /tmp/foo and statically-linked packages will be installed in $SS_DIR(using --prefix option in configure file).
# Replace to yours
SS_DIR=$HOME/ss-libev
mkdir -p "$SS_DIR"
Compile dependencies
mbedTLS
set -euf
VER=$(curl -sL https://api.github.com/repos/ARMmbed/mbedtls/releases/latest | grep '"tag_name":' | cut -d'"' -f4 | tr -d 'v')
wget https://github.com/ARMmbed/mbedtls/archive/v$VER.tar.gz -O mbedtls-$VER.tar.gz
tar xf mbedtls-$VER.tar.gz
pushd mbedtls-$VER
# Install into $SS_DIR
sed -i "s|DESTDIR=/usr/local|DESTDIR=$SS_DIR/mbedtls|" Makefile
CC=gcc AR=ar LD=ld LDFLAGS=-static make -j$(nproc) && make install
# Back to /tmp/foo
popd
libsodium
set -euf
VER=$(curl -sL https://download.libsodium.org/libsodium/releases/ | cut -d'"' -f2 | grep "^libsodium-" | grep "tar\.gz$" | grep "\-stable\." | sort -V | tail -1 | grep -Eo "[0-9]+(\.[0-9]+)+")
wget https://download.libsodium.org/libsodium/releases/libsodium-$VER-stable.tar.gz
tar xf libsodium-$VER-stable.tar.gz
pushd libsodium-stable
./configure --host=$(uname -m)-linux --prefix=$SS_DIR/libsodium --disable-ssp --disable-shared
make -j$(nproc) && make install
popd
pcre
set -euf
VER=$(curl -sL https://ftp.pcre.org/pub/pcre/ | cut -d'"' -f2 | grep "^pcre-" | grep "tar\.gz$" | sort -V | grep -Eo "[0-9]+\.[0-9]+" | tail -1)
wget https://ftp.pcre.org/pub/pcre/pcre-$VER.tar.gz
tar xf pcre-$VER.tar.gz
pushd pcre-$VER
./configure --host=$(uname -m)-linux --prefix=$SS_DIR/pcre --disable-shared --enable-utf8 --enable-unicode-properties
make -j$(nproc) && make install
popd
libev
set -euf
VER=$(curl -sL http://dist.schmorp.de/libev/ | cut -d'"' -f2 | grep "^libev-" | grep "\.tar.gz$" | grep -Eo "[0-9]+\.([0-9]+)+")
wget http://dist.schmorp.de/libev/libev-$VER.tar.gz
tar xf libev-$VER.tar.gz
pushd libev-$VER
./configure --host=$(uname -m)-linux --prefix=$SS_DIR/libev --disable-shared
make -j$(nproc) && make install
popd
c-ares
set -euf
VER=$(curl -sL https://api.github.com/repos/c-ares/c-ares/releases/latest | grep '"name":' | cut -d'"' -f4 | grep -E "^[0-9]+(\.[0-9]+)+$")
URL=$(curl -sL https://api.github.com/repos/c-ares/c-ares/releases/latest | grep browser_download_url | cut -d'"' -f4 | grep "\.tar\.gz$")
wget $URL
tar xf c-ares-$VER.tar.gz
pushd c-ares-$VER
./configure --host=$(uname -m)-linux --prefix=$SS_DIR/c-ares --disable-shared
make -j$(nproc) && make install
popd
Compile shadowsocks-libev statically
You can download latest ss-libev from GitHub API:
VER=$(curl -sL https://api.github.com/repos/shadowsocks/shadowsocks-libev/releases/latest | grep '"tag_name"' | grep -Eo "[0-9]+(\.[0-9]+)+")
wget https://github.com/shadowsocks/shadowsocks-libev/releases/download/v$VER/shadowsocks-libev-$VER.tar.gz
tar xf shadowsocks-libev-$VER.tar.gz
pushd shadowsocks-libev-$VER
# Run the same commands listed below...
Or simply git clone it:
# Build upon HEAD, which functionalities may unstable.
git clone --depth 1 https://github.com/shadowsocks/shadowsocks-libev
pushd shadowsocks-libev
git submodule init
git submodule update
./autogen.sh
LIBS="-lpthread -lm" \
LDFLAGS="-Wl,-static -static -static-libgcc" \
./configure --host=$(uname -m)-linux \
--prefix=$SS_DIR/shadowsocks-libev \
--disable-documentation \
--enable-static \
--with-mbedtls=$SS_DIR/mbedtls \
--with-sodium=$SS_DIR/libsodium \
--with-pcre=$SS_DIR/pcre \
--with-ev=$SS_DIR/libev \
--with-cares=$SS_DIR/c-ares
make -j$(nproc) && make install
popd
Compile simple-obfs
simple-obfs is a simple obfuscating tool(plugin) used in ss-libev, which also can be statically compiled.
git clone --depth 1 https://github.com/shadowsocks/simple-obfs
pushd simple-obfs
git submodule init
git submodule update
./autogen.sh
LIBS="-lpthread -lm" LDFLAGS="-Wl,-static -static -static-libgcc -L$SS_DIR/libsodium/lib -L$SS_DIR/libudns/lib -L$SS_DIR/libev/lib" CFLAGS="-I$SS_DIR/libsodium/include -I$SS_DIR/libudns/include -I$SS_DIR/libev/include" ./configure --host=$(uname -m)-linux --prefix=$SS_DIR/shadowsocks-libev --disable-ssp --disable-documentation
make -j$(nproc) && make install
popd
After all things done, you should have a copy of statically-linked simple-obfs and ss-libev:
[$SS_DIR/shadowsocks-libev/bin]# ls -l
total 19344
-rwxr-xr-x 1 root root 1617280 Aug 2 14:25 obfs-local
-rwxr-xr-x 1 root root 1765240 Aug 2 14:25 obfs-server
-rwxr-xr-x 1 root root 3801592 Aug 2 14:21 ss-local
-rwxr-xr-x 1 root root 1628344 Aug 2 14:21 ss-manager
-rwxr-xr-x 1 root root 5388 Aug 2 14:21 ss-nat
-rwxr-xr-x 1 root root 3737000 Aug 2 14:21 ss-redir
-rwxr-xr-x 1 root root 3965760 Aug 2 14:21 ss-server
-rwxr-xr-x 1 root root 3271912 Aug 2 14:21 ss-tunnel
If you trying detect one of those file, say, ss-local, it’ll shows:
$ file ss-local
ss-local: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=6584349d54fbf0f9e1c389c57ae1394dcbec2543, not stripped
$ ldd ss-local
not a dynamic executable
Which indicates it’s statically-linked(ss-nat is an exception, it’s a shell script).
You can take further steps to strip all symbols, or even pack them up, which can decrease file size significantly.
Before you do anything to the final production, remember to back them up.
# Strip out all symbols
[$SS_DIR/shadowsocks-libev/bin]# find . ! -name 'ss-nat' -type f | xargs strip -s
# NOTE: This should be optional, may make them unstable even erroneous.
[$SS_DIR/shadowsocks-libev/bin]# find . ! -name 'ss-nat' -type f | xargs upx -9
# Also remember to test them
[$SS_DIR/shadowsocks-libev/bin]# find . ! -name 'ss-nat' -type f | xargs upx -t
We’re done, you can now use ss-libev.
FYI, I’ve built ss-libev successfully under Debian 8 x64, its kernel is 3.16.0-4-amd64.