Create a SOCKS proxy on a Linux server with SSH to bypass content filters

Mattias Geniar, Thursday, January 19, 2017 - last modified: Thursday, February 16, 2017

Are you on a network with limited access? Is someone filtering your internet traffic, limiting your abilities? Well, if you have SSH access to any server, you can probably set up your own SOCKS5 proxy and tunnel all your traffic over SSH.

From that point on, what you do on your laptop/computer is sent encrypted to the SOCKS5 proxy (your SSH server) and that server sends the traffic to the outside.

It's an SSH tunnel on steroids through which you can easily pass HTTP and HTTPs traffic.

And it isn't even that hard. This guide is for Linux/Mac OSX users that have direct access to a terminal, but the same logic applies to PuTTy on Windows too.

Set up SOCKS5 SSH tunnel

You set up a SOCKS 5 tunnel in 2 essential steps. The first one is to build an SSH tunnel to a remote server.

Once that's set up, you can configure your browser to connect to the local TCP port that the SSH client has exposed, which will then transport the data through the remote SSH server.

It boils down to a few key actions;

  1. You open an SSH connection to a remote server. As you open that connection, your SSH client will also open a local TCP port, available only to your computer. In this example, I'll use local TCP port :1337.
  2. You configure your browser (Chrome/Firefox/...) to use that local proxy instead of directly going out on the internet.
  3. The remote SSH server accepts your SSH connection and will act as the outgoing proxy/vpn for that SOCKS5 connection.

To start such a connection, run the following command in your terminal.

$ ssh -D 1337 -q -C -N

What that command does is;

  1. -D 1337: open a SOCKS proxy on local port :1337. If that port is taken, try a different port number. If you want to open multiple SOCKS proxies to multiple endpoints, choose a different port for each one.
  2. -C: compress data in the tunnel, save bandwidth
  3. -q: quiet mode, don't output anything locally
  4. -N: do not execute remote commands, useful for just forwarding ports
  5. the remote SSH server you have access to

Once you run that, ssh will stay in the foreground until you CTRL+C it to cancel it. If you prefer to keep it running in the background, add -f to fork it to a background command:

$ ssh -D 1337 -q -C -N -f

Now you have an SSH tunnel between your computer and the remote host, in this example

Use SOCKS proxy in Chrome/Firefox

Next up: tell your browser to use that proxy. This is something that should be done per application as it isn't a system-wide proxy.

In Chrome, go to the chrome://settings/ screen and click through to Advanced Settings. Find the Proxy Settings.

In Firefox, go to Preferences > Advanced > Network and find the Connection settings. Change them as such:

From now on, your browser will connect to localhost:1337, which is picked up by the SSH tunnel to the remote server, which then connects to your HTTP or HTTPs sites.

Encrypted Traffic

This has some advantages and some caveats. For instance, most of your traffic is now encrypted.

What you send between the browser and the local SOCKS proxy is encrypted if you visit an HTTPs site, it's plain text if you visit an HTTP site.

What your SSH client sends between your computer and the remote server is always encrypted.

What your remote server does to connect to the requested website may be encrypted (if it's an HTTPS site) or may be plain text, in case of plain HTTP.

Some parts of your SOCKS proxy are encrypted, some others are not.

Bypassing firewall limitations

If you're somewhere with limited access, you might not be allowed to open an SSH connection to a remote server. You only need to get an SSH connection going, and you're good to go.

So as an alternative, run your SSH server port on additional ports, like :80, :443 or :53: web and DNS traffic is usually allowed out of networks. Your best bet is :443, as it's already an encrypted protocol and less chance of deep packet inspection middleware from blocking your connection because it doesn't follow the expected protocol.

The chances of :53 working are also rather slim, as most DNS is UDP based and TCP is only use in either zone transfers or rare DNS occasions.

Testing SOCKS5 proxy

Visit any "what is my IP" website and refresh the page before and after your SOCKS proxy configuration.

If all went well, your IP should change to that of your remote SSH server, as that's now the outgoing IP for your web browsing.

If your SSH tunnel is down, crashed or wasn't started yet, your browser will kindly tell you that the SOCKS proxy is not responding.

If that's the case, restart the ssh command, try a different port or check your local firewall settings.

Hi! My name is Mattias Geniar. 👋 I'm an independent software developer ⌨️ & Linux sysadmin 👨‍💻, a general web geek & public speaker. Currently working on DNS Spy & Oh Dear! Follow me on Twitter as @mattiasgeniar 🐦.

🔥 If you're stuck with a technical problem, I'm available for hire to help you fix it!

Share this post

Did you like this post? Help me share it on social media! Thanks. 🤗

Have feedback?

New comments have been disabled on this blog, existing comments will remain as-is. Want to give feedback? Is there a mistake in the post?

Send me a tweet on @mattiasgeniar!


Wouter D'Haeseleer Saturday, January 21, 2017 at 12:11 -

I think it’s also worth pointing out that you are also able to do this on an already established SSH session,
Just hit the SSH escape sequence and force your SSH connection to accept command line arguments:


So hit ENTER then ~ and then capital C

Now just add the port forward like on the CLI

-D 1234

for example

Serge van Ginderachter Saturday, January 21, 2017 at 17:58 -

Except when one already multiplexes one’s SSH connections by default.

serge ~ ~C escape not available to multiplexed sessions

Mattias Geniar Saturday, January 21, 2017 at 20:31 -

I think it’s also worth pointing out that you are also able to do this on an already established SSH session

Ooh, that’s a nice trick – didn’t know that. Thanks!

shyam jos Sunday, January 22, 2017 at 10:23 -

will this work if ssl/ssh packet inspection enabled in firewall ?

manu Sunday, January 22, 2017 at 14:03 -

oneliner to connect through the SOCKS proxy:

on linux:

$ google-chrome -proxy-server="socks5://" --host-resolver-rule="MAP *, EXCLUDE"

on mac:

$ open -a /Applications/Google --args --proxy-server="socks5://" --host-resolver-rule="MAP *, EXCLUDE"

Mattias Geniar Monday, January 23, 2017 at 10:49 -

will this work if ssl/ssh packet inspection enabled in firewall ?

Yes, you’re using the SSH protocol to encapsulate all your packets. It’s not a “hack” on SSH, it’s a built-in feature, so it should pass through any DPI firewalls.

Wouter D'Haeseleer Tuesday, January 24, 2017 at 16:01 -

I do have to point out that most DPI firewalls are able to see that you are not sending SSL traffic over port 443 but SSH

In fact even a basic proxy is able to detect this kind of beakout.
(Because SSH starts with exchanging the version as clear text traffic)

To also hide the fact that you are using SSH to tunnel one could create a OpenVPN tunnel over port 443.
SInce openVPN uses the same Negotiation as HTTPS it would be impractical to to dectect this traffic as non HTTPS traffic.

That said a PaloAlto is still able to fingerprint SSL based traffic and filter HTTPS from other SSL stuff.

Ricky Tigg Sunday, January 7, 2018 at 00:43 -

On host using DHCP networking without use of any DNS protection method (DNSCrypt or external DNS such as OpenDNS, Google, Comodo), on QEMU/KVM virtualisation platform, a remote connection using free non-privileged ports which can be forwarded by non-root users, such as ports 1080 and 1337 (ssh -D 1080 -fqCN user@) is established between the Linux guests which are for their part connected to a bridged network interface (

Result from testing DNS leakage regarding that created SOCKS5 proxy revealed that client’s public IPv4 address that, as understood here, should change to the one of the remote SSH server, remains the same as the one without the use of proxy, which is itself the public address of the host; that seems to me expectable. Or could that be then interpreted as a relevant sign for indicating that the ISP is using a technology called ‘Transparent DNS proxy’. which intercepts all DNS lookup requests (TCP/UDP port 53) and forces the user to use ISP’s DNS service for all DNS lookups In that condition, changing the DNS settings to use an ‘open’ DNS service would not be helpful.

Mahdi Thursday, May 10, 2018 at 17:40 -

You are in terminal session to the remote server, so, why you don’t use localhost instead of server name in SSH command?

sop Wednesday, December 5, 2018 at 17:03 -

Won’t work:

$ open -a /Applications/Google –args –proxy-server=”socks5://″ –host-reso

$ open -a /Applications/Google –args –proxy-server=”socks5://″ –host-reso
The file /Users/USERNAME/ does not exist.

The web site has cut off part of your command :(

Jay Wednesday, February 27, 2019 at 17:14 -

On Linux Ubuntu, I am unable to get this to work. Is there an extra step to take if I need to browse to a port of say localhost:3000 ?

jim Sunday, March 10, 2019 at 07:49 -

could you use the chorme extension to establish a SSH connection with SSH arguments at the bottom of the extension -D 1337 -C -q. This way you don’t have to rely on putty or mac terminal to establish a connection but do it all within chrome?