SSH Proxy: Server and Client Side of Using an SSH User Without Shell as Proxy Server

Accessing services on an internal network over a proxy reachable from the Internet.

Imagine you want one of your machines to become a proxy for external users to be able to access local resources or the internet as if they were on that machine. You could run a dedicated proxy server for that, but if the machine provides SSH and you want an easy solution, you can use SSH as well – without risking any shell-related issues (like this user also having access to the local file system).

Why would you want stuff like that in the first place? That’s what proxy servers (and most frequently VPNs) are made for: to access country-, company-, or university-internal resources from outside of that network just as you would from the inside.

Server side

The server side is rather easy. Let’s assume we call that user “sshproxy”. The important thing is to not give your proxy user a shell, which we do here during creation of the user:

sudo useradd -m -d /home/sshproxy -s /bin/false sshproxy # create user and home directory, disable shell

The user’s password is disabled by default (you can check that there’s a ! in /etc/shadow for the sshproxy user). If you don’t want to use passwords but private-public keys (which I would recommend): in /home/sshproxy create the .ssh/ folder and the .ssh/authorized_keys file and ensure they’re readable for the sshproxy user. There you need to add the ssh public keys of people that should be allowed to use the ssh proxy. The cool thing about it is that different real life users can make use of the same sshproxy user: you just need to add to manage the keys of real life users for the sshproxy user. Further, you likely don’t want the sshproxy user to be able to change the authorized keys, therefore make the file read only for that user (e.g. root owned + writeable by owner only). If you have an AllowUsers section in your /etc/ssh/sshd_config, you need to add the sshproxy user there and restart ssh. That’s it on the server side.

User side

If you’re one of the users that need to generate their ssh keypair, you can have a look at:
(very easy to understand)
(details that are good to know if you want to have more secure keys = not so easy to crack)

If you use RSA then use at least 2048 bit key length (4096 can’t hurt…), e.g. with ssh-keygen with the “-b 4096” parameter. If you’re on a Windows machine: you can do the same using e.g. Putty. Don’t forget to use a good password to protect your private key file (usually the “id_rsa” file) and never disclose it – servers only need your public key (usually “”).

Using the proxy via Linux shell

Everything’s built in, just use the following command.

ssh -D 8080 -N sshproxy@YOUR-IP-OR-URL -p YOUR-PORT

This command opens the local port 8080 (on the client machine) for proxy tasks. YOUR-PORT-URL and YOUR-PORT correspond to the SSH server running on the server machine. If everything worked fine you won’t get any response in the shell – just leave the terminal open. Make sure your private key file is in ~/.ssh/id_rsa or provide it explicitly with “-i”. If you can’t access the server try removing the “-N”. Then you should see that the server logs you in and out immediately (this means everything works fine from the SSH, proxy and tunnel side – if you add -N again, you should be fine therefore). You can check your local opened ports with nmap (“nmap localhost”). If port 8080 is not in the list before login and opened after login your tunnel works.

Using the proxy via Putty

  • address: YOUR-IP-OR-URL (where SSH server is running)
  • port: YOUR-PORT (where SSH server is running)
  • user: sshproxy
  • Enable the check box “Don’t start a shell or command at all” in “Connection-SSH”
  • Specify your private key in “Auth”
  • Tunnels: add a “dynamic tunnel” on “local port 8080”, leave destination open (should state “D8080” in Putty after you apply)

Sending data to your local port

As you now have a tunnel on port 8080 on your local machine open, you need to send request to this port, instead of your standard gateway. E.g. for your browser you can achieve that configuring the browser to use a proxy (e.g. Firefox: FoxyProxy AddOn: set address “localhost” and port “8080”).

Btw: you can do other cool things with that proxy as well, such as reverse port tunnelling, circumventing firewalls etc. But you should ensure that this is allowed in the company/country you’re in before you get yourself into troubles.

Around the Firewall: ssh proxy and ssh port forwarding

If you happen to a) be behind a firewall which does not allow you to reach a certain destination on the web, or b) be outside in the web and cannot access a certain destination inside a network, the openssh implementation may help you: from the machine you’re sitting at (“local machine”) you just need ssh access to e.g. a Linux machine with an ssh-server running in the “target network” (“remote machine”, for a) outside the firewall in the “web”, for b) inside the target network behind the firewall).

a) ssh proxy (built in SOCKS proxy)

When logging in to the remote machine, use the -D option:

ssh -p 22 user_name@remote_machine_url -D 8080
  • -p 22 specifies the port the ssh server listens on at the remote machine.
  • -D 8080 specifies that requests sent to port 8080 at your locale machine are tunnelled to the remote machine, and then routed to where ever they should go. This way you can sent packets transparently to their targets over the remote machine.

For usage with a web browser, you then need to configure the browser so that it uses a proxy instead of your default gateway (e.g. for Firefox, you can use the FoxyProxy plugin). Configure it so that the browser uses a SOCKS proxy and routes packets to your local machine on port 8080.

b) ssh port forwarding

When logging in to the remote machine, use the the -L and/or the -R  option:

ssh -p 22 user_name@remote_machine_url -L 10001: -R 10003:
  • -p 22 specifies the port the ssh server listens on at the remote machine.
  • -L 10001: specifies that requests sent to port 10001 at your locale machine are tunnelled to the machine at in the remote machine’s network on port 10002. This way you can sent packages from your machine to a machine in the remote machine’s network without needing direct access to it.
  • -P 10003: specifies that requests sent to port 10003 at the remote machine are forwarded to the machine on in your locale machine’s network on port 10004. This way somebody else from the remote machine’s network — which does not have any access to your locale machine’s network from outside — still can access a machine in your network.

On Windows you can do the same using Putty. You need to enable the check box “Don’t start a shell or command at all” in “Connection-SSH”. At “Tunnels”: add a “dynamic tunnel” on “local port X” where X is the port you are going to send data to locally (leave destination open – should state something like “D8080” after adding then).