JAMES
LOPER

How to run a server behind a firewall without port forwarding

Normally without sufficient access to the router, it’s not possible to expose your computer to the internet so it can act as a server. This is often the case, you have a powerful computer behind internet you have no control over. Here I will show the best way to circumvent that via a gateway server.

I initially wanted to create a sort of hollow gateway to the network interface on the target server, however this is actually a real waste of the gateway server. The gateway could serve other apps, or proxy more than one remote computer. A better way would be to use name-based virtual hosts to route incoming requests to the right server. In this guide I use NGINX to handle requests and routing, SSH to handle the forwarding, and systemd to ensure SSH stays connected at all times.

Here is the config file for ssh for convenience

sudo nano /etc/ssh/sshd_config
sudo service ssh restart

Configure the target computer for basic usage of SSH RemoteForward

We need to make the target computer reach out to the proxy to initiate the forwarding. Edit ~/.ssh/config and add the following hostname block. This forms the groundwork for all to come.

Host proxy
  HostName example.com
  User ubuntu
  RemoteForward 4000 localhost:4000
  ServerAliveInterval 10

At this point, if you run ssh proxy on the target computer, you’ll be able to navigate to example.com:4000 If that’s all you need, great! Next we’ll bulk up this thing by daemonizing it and integrating with NGINX.

Configure SSH public key authentication

Since this is going to be a daemon, there will be no prompt for the SSH password, so the remote server is going to have must authenticate with a public key.

ssh-keygen -t rsa
ssh-copy-id ubuntu@example.com

Test your new configuration with ssh proxy and you should be able to login without a password prompt. Make sure you can do this now because it’ll be harder to diagnose once you begin daemonizing it.

Use systemctl to daemonize the SSH RemoteForward process

In Ubuntu, systemctl is ideally suited for this, since it supports waiting until network access is established after boot, and can restart the process when it exits. Create the following config file in /etc/systemd/system/proxy.service

[Unit]
Description=Proxy
After=network-online.target

[Service]
Restart=always
RestartSec=20
User=ubuntu
ExecStart=/bin/ssh -NT proxy

[Install]
WantedBy=multi-user.target

After making the service file, you must reload systemd, then start it for the first time and enable it to launch at boot.

sudo systemctl daemon-reload
sudo systemctl start proxy
sudo systemctl enable proxy

You can diagnose any problems by checking the log with journalctl -u proxy.service

Install the latest NGINX on the proxy server

sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt install nginx

Set up host names to forward traffic to the remote computer

Add a new virtual host, in this guide, the proxy server will have the hostname proxy.example.com and forward to port 4000. Edit the NGINX config file at /etc/nginx/sites-enabled/default

server {
  listen 80;
  server_name proxy.example.com;
  location / {
    proxy_pass http://localhost:4000;
  }
}

Restart NGINX with sudo service nginx reload. You can now go to proxy.example.com and it should forward to port 4000 on the target computer!