SSH SOCKS Proxy: Create a SOCKS5 Tunnel for Browsing

By 

•

Updated on

•

10 min read

Set up SSH SOCKS Tunnel for Private Browsing

There are times when you want to route browser traffic through a remote server, access content from another network, or bypass an intermediate firewall.

One option is to use a VPN, but that requires installing client software on your machine and setting up your own VPN server or subscribing to a VPN service.

The simpler alternative is to route your local browser traffic through an encrypted SSH SOCKS proxy. Applications configured to use the proxy connect to the SSH server first, and the server forwards the traffic to the final destination.

An SSH SOCKS proxy changes the exit IP address and encrypts traffic between your computer and the SSH server. It does not make browsing anonymous, and DNS requests can still leak unless your browser is configured to proxy DNS through the tunnel.

This tutorial walks you through the process of creating an encrypted SSH tunnel and configuring Firefox and Google Chrome web browsers to use a SOCKS proxy.

Quick Reference

For a printable quick reference, see the SSH cheatsheet .

TaskCommand
Create SOCKS tunnelssh -N -D 127.0.0.1:9090 user@server
Run tunnel in backgroundssh -fN -D 127.0.0.1:9090 user@server
Use custom SSH portssh -N -D 127.0.0.1:9090 -p 2222 user@server
Start tunnel from SSH configssh -N socks-tunnel
Check local listener on Linuxss -ltnp | grep 9090
Test through tunnelcurl --socks5-hostname 127.0.0.1:9090 https://ifconfig.me

Prerequisites

  • Server running any flavor of Linux, with SSH access to route your traffic through it.
  • Web browser.
  • SSH client.

Set Up the SSH Tunnel

We will create an SSH tunnel that opens a local SOCKS proxy on 127.0.0.1:9090 and forwards traffic through the SSH server. You can use any free local port number of 1024 or higher; only root can open the privileged ports below 1024.

Linux and macOS

If you run Linux, macOS or any other Unix-based operating system on your local machine, you can easily start an SSH tunnel with the following ssh command:

Terminal
ssh -N -D 127.0.0.1:9090 user@server

The options used are as follows:

  • -N - Tells SSH not to execute a remote command.
  • -D 127.0.0.1:9090 - Opens a SOCKS tunnel bound to localhost on port 9090.
  • user@server - Your remote SSH user and server IP address or hostname.

You can also add the following options:

  • -f - Sends ssh to the background after authentication. For example, ssh -fN -D 127.0.0.1:9090 user@server runs the tunnel in the background.
  • -p PORT_NUMBER - Connects to an SSH server that is listening on a port other than 22 .

Binding the SOCKS listener to 127.0.0.1 keeps it available only on your local machine. Once you run the command, you will be prompted to enter your user password. After entering it, the SSH tunnel will be established.

With -N, the command does not open a remote shell and prints nothing after you log in. The terminal looks idle, but the tunnel is running and stays open until you press Ctrl+C.

You can set up SSH key-based authentication and connect to your server without entering a password.

Using the SSH Config File

Typing the full command every time gets tedious. You can save the tunnel settings as a host entry in your SSH config file :

~/.ssh/configini
Host socks-tunnel
    HostName server_ip
    User user
    DynamicForward 127.0.0.1:9090
    ExitOnForwardFailure yes
    ServerAliveInterval 60

Replace server_ip and user with your server address and SSH username. The tunnel-related directives are:

  • DynamicForward 127.0.0.1:9090 - The config file equivalent of the -D 127.0.0.1:9090 option.
  • ExitOnForwardFailure yes - Makes ssh exit when it cannot open the local port. Without it, ssh stays connected without the SOCKS proxy.
  • ServerAliveInterval 60 - Sends a keepalive message when the server has been silent for 60 seconds. This keeps routers and firewalls from dropping an idle tunnel.

To start the tunnel, pass the host alias to ssh:

Terminal
ssh -N socks-tunnel

Windows

Windows 10 and Windows 11 include a built-in OpenSSH client. Open PowerShell or Command Prompt and run the same command as on Linux:

powershell
ssh -N -D 127.0.0.1:9090 user@server

If you prefer a graphical client, you can create the tunnel with PuTTY instead. You can download PuTTY here .

  1. Launch PuTTY and enter your server IP address in the Host Name (or IP address) field.

    PuTTY Session page with the server IP address in the Host Name field
  2. Under the Connection menu, expand SSH and select Tunnels. Enter the port 9090 in the Source port field, and check the Dynamic radio button.

    PuTTY Tunnels page with source port 9090 and the Dynamic option selected
  3. Click on the Add button as shown in the image below.

    PuTTY Tunnels page with the D9090 dynamic forward in the Forwarded ports list
  4. Go back to the Session page to save the settings so that you do not need to enter them each time. Enter the session name in the Saved Sessions field and click on the Save button.

    PuTTY Session page with my-proxy entered in the Saved Sessions field
  5. Select the saved session and log in to the remote server by clicking on the Open button.

    PuTTY Session page with the saved my-proxy session selected

    A terminal window asking for your username and password will open. Once you enter your username and password, you will be logged in to your server and the SSH tunnel will be started.

    Setting up public key authentication will allow you to connect to your server without entering a password.

Configuring Your Browser to Use Proxy

Now that you have opened the SSH SOCKS tunnel, the last step is to configure your preferred browser to use it.

Firefox

The steps below are the same for Windows, macOS, and Linux.

  1. In the upper right-hand corner, click on the hamburger icon ☰ to open Firefox’s menu.

  2. Click on the ⚙ Settings link.

  3. Select Privacy and security in the left sidebar.

  4. Scroll down to the Connection and software security section and click on Advanced settings.

  5. Under Proxy settings, click on Configure proxy. The Connection Settings window will open.

    • Select the Manual proxy configuration radio button.
    • Enter 127.0.0.1 in the SOCKS Host field and 9090 in the Port field.
    • Make sure SOCKS v5 is selected.
    • Make sure the Proxy DNS when using SOCKS v5 checkbox is checked. Current Firefox versions enable it by default.
    • Click on the OK button to save the settings.
    Firefox Connection Settings window with a manual SOCKS v5 proxy on 127.0.0.1 port 9090

Older Firefox releases, such as Firefox ESR 140, use the previous settings layout. In those versions, open the General panel, scroll down to Network Settings, and click on the Settings... button.

At this point, Firefox is configured and you can browse through the SSH tunnel. To verify, open a search engine and search for “what is my ip”. The displayed IP address should be the IP address of your SSH server.

To restore the default settings, open the Connection Settings window again, select the Use system proxy settings radio button, and save the settings.

There are also several plugins that can help you to configure Firefox’s proxy settings such as FoxyProxy .

Google Chrome

Google Chrome uses the default system proxy settings. Instead of changing your operating system proxy settings, you can start Chrome from the command line with a separate profile.

To launch Chrome using a new profile and your SSH tunnel use the following command:

Linux:

Terminal
/usr/bin/google-chrome \
    --user-data-dir="$HOME/proxy-profile" \
    --proxy-server="socks5://127.0.0.1:9090" \
    --host-resolver-rules="MAP * ~NOTFOUND, EXCLUDE 127.0.0.1"

macOS:

Terminal
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
    --user-data-dir="$HOME/proxy-profile" \
    --proxy-server="socks5://127.0.0.1:9090" \
    --host-resolver-rules="MAP * ~NOTFOUND, EXCLUDE 127.0.0.1"

Windows Command Prompt:

bat
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
    --user-data-dir="%USERPROFILE%\proxy-profile" ^
    --proxy-server="socks5://127.0.0.1:9090" ^
    --host-resolver-rules="MAP * ~NOTFOUND, EXCLUDE 127.0.0.1"

Run this example in Command Prompt (cmd.exe); its line continuations and environment-variable syntax do not work in PowerShell.

On older Windows installations, Chrome may be located in C:\Program Files (x86)\Google\Chrome\Application\ instead.

The profile will be created automatically if it does not exist. This way you can run multiple instances of Chrome at the same time.

The separate profile is required. Without it, the command only opens a new window in the Chrome instance that is already running, and the --proxy-server flag is ignored.

With the socks5:// scheme, Chrome sends hostnames for proxied web requests to the SSH server for resolution. Other Chrome components can still issue local DNS requests. The additional --host-resolver-rules flag blocks lookups through Chrome’s local resolver, except for the proxy address. These settings do not guarantee that every Chrome component or extension uses the tunnel. See Chromium’s SOCKS proxy documentation for details.

To confirm the SSH tunnel is working properly, search for “what is my ip”. The IP shown in your browser should be the IP address of your SSH server.

Verifying the SOCKS Proxy

On Linux, you can verify the local SOCKS listener from the terminal:

Terminal
ss -ltnp | grep 9090

The output will be something like this:

output
LISTEN 0      128        127.0.0.1:9090      0.0.0.0:*    users:(("ssh",pid=4607,fd=4))

The ssh process is listening on 127.0.0.1:9090. If the command prints nothing, the tunnel is not running.

On macOS, check the listener with lsof instead:

Terminal
lsof -nP -iTCP:9090 -sTCP:LISTEN

Look for an ssh process listening on 127.0.0.1:9090.

On Windows, run the following command in PowerShell:

powershell
Get-NetTCPConnection -LocalPort 9090 -State Listen

The result should show 127.0.0.1 under LocalAddress and 9090 under LocalPort. If no matching connection exists, PowerShell reports that it cannot find a matching object.

To test the tunnel without changing browser settings, send a request through the SOCKS proxy:

Terminal
curl --socks5-hostname 127.0.0.1:9090 https://ifconfig.me

The output should show the public IP address of your SSH server. The --socks5-hostname option sends DNS lookups through the SOCKS proxy, which helps avoid local DNS leaks.

In Windows PowerShell, use curl.exe instead of curl so the command runs curl rather than the Invoke-WebRequest alias used by Windows PowerShell 5.1.

Troubleshooting

bind [127.0.0.1]:9090: Address already in use
Another process is already using port 9090. The SSH connection still opens, but without the SOCKS proxy. Pick a different local port, such as 1080, and update the browser proxy settings to match. To make ssh exit instead of connecting without the proxy, add -o ExitOnForwardFailure=yes.

channel 1: open failed: administratively prohibited: open failed
The SSH server is blocking forwarding or the requested destination. Requests through the proxy fail, and ssh prints this line for each blocked connection. On the server, check the effective settings for the affected account, including any applicable Match rules:

Terminal
sudo sshd -T -C user=user,addr=CLIENT_IP,host=CLIENT_HOSTNAME | grep -Ei 'allowtcpforwarding|disableforwarding|permitopen'

Replace user, CLIENT_IP, and CLIENT_HOSTNAME with the SSH username and the client’s source IP address and resolved hostname as seen by the server. Plain sshd -T does not evaluate connection-specific Match rules. If your rules also match the server address or port, include laddr=SERVER_IP,lport=SSH_PORT in the -C argument.

For this tunnel, AllowTcpForwarding must be local, yes, or all, DisableForwarding must be no, and PermitOpen must allow the requested destinations. If you use public key authentication, also check the matching entry in ~/.ssh/authorized_keys for no-port-forwarding, restrict, or permitopen options. These SSH hardening settings can block forwarding even when the global settings allow it. Adjust only the intended account’s restrictions, validate configuration changes with sudo sshd -t, reload the SSH service, and reconnect the tunnel.

Permission denied (publickey)
The SSH server did not accept your key. Check that your public key is installed on the server, or connect with the correct username and key file. For a step-by-step walkthrough, see the SSH Permission denied (publickey) guide .

The browser still shows your local IP
Confirm the tunnel is running with the listener check for your operating system above, then check that the browser is using 127.0.0.1 as the SOCKS host and 9090 as the port. If Chrome ignores the proxy, close any Chrome window that already uses the same --user-data-dir profile and run the command again.

DNS still resolves locally
In Firefox, make sure Proxy DNS when using SOCKS v5 is enabled. In Chrome, use both the --proxy-server and --host-resolver-rules flags shown above. For command-line tests, use curl --socks5-hostname instead of curl --socks5.

The tunnel closes when the terminal closes
Run the SSH command with -fN (for example, ssh -fN socks-tunnel), or start it inside tmux or screen .

The tunnel drops after a few minutes of inactivity
A router or firewall between you and the server is closing the idle connection. Add -o ServerAliveInterval=60 to the ssh command, or set ServerAliveInterval 60 in the host entry in your SSH config. For more details, see the SSH broken pipe guide .

Conclusion

An SSH SOCKS proxy routes your browser traffic through any server you can reach over SSH, with no VPN software to install. For easier reuse, wrap ssh -fN socks-tunnel and the Chrome launch command in a Bash alias so one command starts both.

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 1000+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page