Good evening!

This is a quick recipe on how to deploy your own SOCKS5 server which can be used in web browser or Telegram messenger. Or anything that supports such a proxy. Additionally, authentication will be set up.

In the past, I tried to run a SOCKS5 server which didn’t have authentication. Even though I had no domain name, it was probably found by somebody and added to some kind of a free proxy list, because after a while my server was completely overrun by some other users. So, lesson learnt, authentication is a must out in the wild.

Dante configuration file

We will use dante as our proxy server. Here’s what sockd.conf, the configuration file, looks like.

# the server will log both via syslog, to stdout and to /var/log/sockd.log
#logoutput: syslog stdout /var/log/sockd.log
logoutput: stderr

# The server will bind to the address 10.1.1.1, port 1080 and will only
# accept connections going to that address.
#internal: 10.1.1.1 port = 1080
# Alternatively, the interface name can be used instead of the address.
#internal: eth0 port = 1080
internal: 0.0.0.0 port = 1080

# all outgoing connections from the server will use the IP address
# 195.168.1.1
#external: 192.168.1.1
external: eth0
external.rotation: route

# methods for socks-rules.
socksmethod: username

# methods for client-rules.
clientmethod: none


#
# User identities, an important section.
#

# when doing something that can require privilege, it will use the
# userid "sockd".
#user.privileged: sockd

# when running as usual, it will use the unprivileged userid of "sockd".
user.unprivileged: sockd

# If you are not using libwrap, no need for the below line, so leave
# it commented.
# If you compiled with libwrap support, what userid should it use
# when executing your libwrap commands?  "libwrap".
#user.libwrap: libwrap


#
# Some options to help clients with compatibility:
#

# when a client connection comes in the socks server will try to use
# the same port as the client is using, when the socks server
# goes out on the clients behalf (external: IP address).
# If this option is set, Dante will try to do it for reserved ports as well.
# This will usually require user.privileged to be set to "root".
#compatibility: sameport

# If you are using the Inferno Nettverk bind extension and have trouble
# running servers via the server, you might try setting this.
#compatibility: reuseaddr

#
# The Dante server supports some extensions to the socks protocol.
# These require that the socks client implements the same extension and
# can be enabled using the "extension" keyword.
#
# enable the bind extension.
#extension: bind


#
# Misc options.
#

# how many seconds can pass from when a client connects til it has
# sent us it's request?  Adjust according to your network performance
# and methods supported.
#timeout.negotiate: 30   # on a lan, this should be enough.

# how many seconds can the client and it's peer idle without sending
# any data before we dump it?  Unless you disable tcp keep-alive for
# some reason, it's probably best to set this to 0, which is
# "forever".
#timeout.io: 0 # or perhaps 86400, for a day.

# do you want to accept connections from addresses without
# dns info?  what about addresses having a mismatch in dns info?
#srchost: nodnsunknown nodnsmismatch

#
# The actual rules.  There are two kinds and they work at different levels.
#
# The rules prefixed with "client" are checked first and say who is allowed
# and who is not allowed to speak/connect to the server.  I.e the
# ip range containing possibly valid clients.
# It is especially important that these only use IP addresses, not hostnames,
# for security reasons.
#
# The rules that do not have a "client" prefix are checked later, when the
# client has sent its request and are used to evaluate the actual
# request.
#
# The "to:" in the "client" context gives the address the connection
# is accepted on, i.e the address the socks server is listening on, or
# just "0.0.0.0/0" for any address the server is listening on.
#
# The "to:" in the non-"client" context gives the destination of the clients
# socks request.
#
# "from:" is the source address in both contexts.
#


#
# The "client" rules.
#

# Allow everyone to connect to this server.
client pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    log: connect error  # disconnect
}

# Allow all operations for connected clients on this server.
socks pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    command: bind connect udpassociate
    log: error  # connect disconnect iooperation
    #socksmethod: username
}
# Allow all inbound packets.
socks pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    command: bindreply udpreply
    log: error  # connect disconnect iooperation
}

I have provided the full file (deleting some commented lines), but it is actually the default Dante config file with only one change: socksmethod: username, instead of none. This will ensure that only authenticated users will connect. You may ask, where do you put the user credentials though? Actually, it reads a usual Linux system user, the one you create using adduser. But you don’t need to think about it now, it will be taken care of when we build our container.

Building image

The recipe for the docker container was actually stolen referenced from here.

FROM alpine:3.8

RUN apk add --no-cache linux-pam && apk add --no-cache -t .build-deps build-base curl linux-pam-dev \
&& cd /tmp \
&& curl -L https://www.inet.no/dante/files/dante-1.4.2.tar.gz | tar xz && cd dante-* \
&& ac_cv_func_sched_setscheduler=no ./configure && make install \
&& adduser -S -D -u 8062 -H sockd \
&& printf 'mycoolpassword\nmycoolpassword\n' | adduser johnnyproxier

COPY sockd.conf /etc/

CMD ["sockd"]

The original Dockerfile contains much more than this, but I didn’t find it necessary. Essentially, it installs the needed dependencies and Dante itself and creates required users. Pay attention to the last line in RUN, this is where the authentication credentials are created. Replace johnnyproxier with the desired username and mycoolpassword with password. Attention! \n (the newline symbol) should remain, because when you call adduser it asks for a password twice, and printf simulates you typing it in (and pressing Enter at newlines).

Now let’s create the image. Run docker build -t dante-auth. It creates the dante-auth image which you can use to run your container.

Running container and connecting to the proxy server

Now all that’s left is to run docker run -d -p 1080:1080 dante-auth.

-d Means daemonize, or run in background. We have also opened the port 1080 which is used to connect to the proxy server.

Now you can test it. The simple way is via curl --proxy socks5://111.111.111.111 --proxy-user johnnyproxier:mycoolpassword ifconfig.co, where 111.111.111.111 is the IP address of your server, and you should set your user credentials as well. You can query any site this way; ifconfig.co simply shows the IP address. If it is the IP of your proxy server, then it works fine.

Conclusion

Congratulations, you have set up your own proxy server. Just as a final tip: I use Firefox, and even though it has a built-in support for proxies, it doesn’t seem to support (at least for me) authentication. So I use FoxyProxy, which allows you to create settings for your proxy and toggle it via a menu in control bar at any time.

Thanks for tuning in. I’ll see you eventually.