Skip to content

Instantly share code, notes, and snippets.

@markuskreitzer
Last active January 1, 2024 22:06
Show Gist options
  • Save markuskreitzer/f08dc47eb57135b55c0ddb6862fc6df0 to your computer and use it in GitHub Desktop.
Save markuskreitzer/f08dc47eb57135b55c0ddb6862fc6df0 to your computer and use it in GitHub Desktop.
How do set up a persistent reverse proxy on Ubuntu Linux

Create a secure SSH server with a static IP or DNS entry. It is important to set up keys and cache public key of destination server prior to these steps. There are many guides on doing this, so we'll skip over those.

The Script

Create a script with the following content. You can save it as /root/revese_ssh.sh for this example.

#!/usr/bin/env bash

REMOTE_PORT=22
LOCAL_PORT=22
REMOTE_HOST="ssh.example.com"
USER="cli_commander"

while true; do
    # Check if the reverse tunnel is already established
    if ! nc -z localhost $REMOTE_PORT; then
        # If not, establish the tunnel
        ssh -N -R $REMOTE_PORT:localhost:$LOCAL_PORT $USER@$REMOTE_HOST
    else
	echo "Tunnel already established."
    fi
    # Wait for 30 seconds before checking again
    sleep 30
done

Make sure you give it execute permissions if you are going to execute it directly: chmod u+x /root/reverse_ssh.sh

The Service

Create a service definition to persistently keep this script running:

sudo vi /etc/systemd/system/reverse_ssh_tunnel.service

File content:

[Unit]
Description=Reverse SSH Tunnel Service
After=network.target

[Service]
User=c
ExecStart=/root/reverse_ssh.sh
Restart=always

[Install]
WantedBy=multi-user.target

To enable the service, run the following:

sudo systemctl daemon-reload
sudo systemctl enable reverse_ssh_tunnel.service
sudo systemctl start reverse_ssh_tunnel.service

To check the status:

sudo systemctl status reverse_ssh_tunnel.service

The Use

You can configure your ~/.ssh/config file to automatically log into this server by jumping through your SSH Gateway Server.

Host ssh.example.com
  Hostname ssh.example.com
  User cli_commander
  Port 22
  IdentityFile ~/.ssh/id_rsa_ssh_example_com
  
Host myPC
    Hostname localhost
    User tintin
    Port 12345
    ProxyJump ssh.example.com

To log into the server with this ssh configuration, all you need to do is,

ssh myPC

Alternatively, if you don't have this configuration set up, you can ssh into your jump server,

ssh ssh.example.com

And then, log into your remote system via the reverse proxy:

ssh ssh://tintin@localhost:12345/

The Risk

If either machine is compromised, it will give an attacker access to any or all machines running.

#!/bin/bash
# Variables
REMOTE_PORT=22
LOCAL_PORT=22
REMOTE_HOST="ssh.example.com"
USER="cli_commander"
SERVICE_FILE="/etc/systemd/system/reverse_ssh_tunnel.service"
SSH_CONFIG="$HOME/.ssh/config"
KNOWN_HOSTS="$HOME/.ssh/known_hosts"
# Import remote server's SSH key
ssh-keyscan -H $REMOTE_HOST >> $KNOWN_HOSTS
# Create reverse SSH script
cat << EOF > /root/reverse_ssh.sh
#!/usr/bin/env bash
while true; do
if ! nc -z localhost $REMOTE_PORT; then
ssh -N -R $REMOTE_PORT:localhost:$LOCAL_PORT $USER@$REMOTE_HOST
else
echo "Tunnel already established."
fi
sleep 30
done
EOF
# Give execute permissions
chmod u+x /root/reverse_ssh.sh
# Create systemd service
cat << EOF > $SERVICE_FILE
[Unit]
Description=Reverse SSH Tunnel Service
After=network.target
[Service]
User=root
ExecStart=/root/reverse_ssh.sh
Restart=always
[Install]
WantedBy=multi-user.target
EOF
# Enable and start the service
systemctl daemon-reload
systemctl enable reverse_ssh_tunnel.service
systemctl start reverse_ssh_tunnel.service
# Configure SSH to use the reverse tunnel
cat << EOF >> $SSH_CONFIG
Host ssh.example.com
Hostname ssh.example.com
User cli_commander
Port 22
IdentityFile ~/.ssh/id_rsa_ssh_example_com
Host myPC
Hostname localhost
User tintin
Port 12345
ProxyJump ssh.example.com
EOF
echo "Installation and configuration complete."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment