Easy ways to setup Reverse Proxy for NAT-Passthrough
It's time to abandon NPS, Frp, or other solutions that are hard to configure or no longer maintained. Thanks to Docker, it's possible to set up a reliable reverse proxy with single command.
Make sure you have a machine with a public IP address (it could be a VPS), otherwise our method may not be applicable. Let's take exposing the SSH port of a machine behind NAT as an example. There are three roles in total:
- Local Machine: The machine behind NAT firewall with a local IP address, and you want to expose its SSH port 22 to the public network.
- Public Server: The machine with a public IP address (a.b.c.d). Typically you rent it from a public cloud service provider like AWS or Azure. Its port 22 is also open and being used by its own SSH service.
- Your Computer: Another machine you are currently using.
(Recommended) Persistent Method: via Gost with Docker
Before getting started: Install Docker
The first step is to install the Docker on both the local machine and the public server. For Ubuntu 18.04+, I personally prefer to install Docker through apt.
local-machine&public-server$ sudo apt update
(Recommended) Using Websocket + TLS + Gost Relay Protocol
Gost supports nuermous proxy protocols. For reliablity, it is suggested to use a secured protocol to resist the interference by some secure gateways like GFW. Luckily, with the help of Docker, it is very easy to set up a secured tunnel. Another good news is that Docker Daemon will help to monitor the service and automatically restart Gost Service at boot or on failure. Let's say goodbye to the annoying Systemd.
On Public Server
cd ~ # other any other path you like
On Local Machine
docker run --name gost_client --net host -id --restart always --entrypoint "" gogost/gost gost -L rtcp://:<remote_port>/:<local_port> -F "relay+wss://<user>:<passwd>@<pub_server_ip_or_domain>:<gost_service_port>"
Here is the explanation of parameters:
passwd: The username and the password for Gost. They are irrelevant to any other account such as Linux accounts.
pub_server_ip_or_domain: It could be either the public IP address or the binded domain name. If you would like to use your valid SSL certificate issued by CA, you should only use the domain name here.
gost_service_port: Could be arbitrary value. It is also fine to set this port number to 443 to pretend as a HTTPS server.
remote_port: The port that the public server's Gost listens to. The data received from this port will be forwarded to
local_porton the local machine. It could be arbitrary value.
local_port: The port that should associate with some services on the local machine. In our case, it should be 22, the SSH port.
Back to our case, the corresponding commands will be:
# On Public Server
After that, the SSH port 22 on the local machine should be mapped to the port 2022 on the public server now.
# user-local is the name of the user on local machine
Debugging Tips: If Gost is not working properly, we can read the log using the command below.
1 docker logs -f gost_server # or gost_client
(Optional) Using your SSL certificate
By default, Gost will generate a self-signed SSL certificate if the user doesn't specify one. However, this might be considered unsafe as the communication is no longer able to defense the MITM attack. Moreover, some secure gateways may disrupt the TLS session with a self-signed certificate.
The solution is simple. Do you remember the
gost directory we created before? We just need to put our certificate there and restart the service. There should be two files in total,
key.pem, and their content should start with
-----BEGIN CERTIFICATE---- and
-----BEGIN RSA PRIVATE KEY----- respectively.
Lastly, the command to restart the service is:
# On Public Server
Temporary Method: via OpenSSH Client
If you don't want to install any new software, we can also utilize SSH to build a tunnel. This method is also simple (sometimes), but it is not quite reliable. As you might know, a SSH connection can be easily disrupted due to many reasons. In our case, we just need to type this command on the local machine to set up a tunnel:
local-machine$ ssh -R "[::]:2022:localhost:22" email@example.com
If everything goes well, now you can connect to the local machine through:
your-computer$ ssh firstname.lastname@example.org -p 2022
However, if you failed to connect to your local machine. Please check the
sshd configuration on the public server.
public-server$ sudo nano /etc/ssh/sshd_config
Find the following line (for nano editor, press Ctrl-W to search), uncomment, and replaced
Then restart the SSH server.
public-server$ sudo service sshd restart