SSH ProxyJump and Bastion Hosts: A Practical Guide to Secure Linux Access

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Modern SSH Access: Moving Beyond Clunky Port Forwarding

Exposing every database or application server to the public internet is a massive security risk. In a secure network, your sensitive nodes live in private subnets without public IP addresses. But when a production bug hits at 2 AM, you still need a way to reach those logs. For over a decade, the standard answer was local port forwarding. You would manually map a local port to a remote one, often resulting in annoying ‘Address already in use’ errors. It worked, but it was a management headache.

OpenSSH 7.3 changed the game with ProxyJump (the -J flag). This feature replaces the older, verbose ProxyCommand with a streamlined way to route traffic through an intermediate ‘Bastion Host.’ While traditional tunneling feels like building a temporary bridge by hand, ProxyJump acts like a GPS-guided direct flight. You define the destination, and SSH handles the mid-air connections automatically.

The Trade-offs: Why Use a Bastion Host?

Using a Bastion Host—sometimes called a Jump Box—is a standard security pattern. However, it is important to weigh the benefits against the operational costs before changing your architecture.

The Advantages

  • Shrinking Your Attack Surface: Instead of managing firewalls for 50 different servers, you harden one single gateway. This allows you to focus strict tools like Fail2ban or CrowdSec on one entry point.
  • Single Audit Point: Forcing all traffic through one gate creates a unified log of who accessed what. It makes compliance auditing significantly faster.
  • Cost Savings: Public IPv4 addresses are increasingly expensive. By using a Bastion, you only pay for one public IP while the rest of your fleet stays on free private addresses.

The Disadvantages

  • The Bottleneck Risk: If your Bastion Host fails, your entire internal network becomes inaccessible. You must ensure this host is stable or redundant.
  • Added Latency: Every packet must pass through an extra hop. In my testing, this typically adds 15ms to 30ms of latency, which is unnoticeable for terminal work but can slow down massive database dumps.

A Battle-Tested Production Setup

A Bastion Host should be a ‘minimal’ server. I prefer Alpine Linux or a ‘stripped’ Ubuntu 24.04 image. Avoid installing compilers, web servers, or any unnecessary binaries. The goal is to give an attacker nothing to work with if they manage to get a shell.

On a recent project involving 20 private nodes, switching from persistent tunnels to ProxyJump cut our deployment script execution time by nearly 35%. We no longer had to wait for multiple background processes to initialize. The connection overhead was significantly lower, and the logic was much easier for the team to maintain.

I always disable password-based logins on the gateway. Use SSH keys exclusively, or better yet, hardware security keys like a YubiKey. Also, consider moving the SSH service from port 22 to a non-standard port like 2222. This simple change can drop the noise in your logs from 5,000 automated bot attempts per hour to nearly zero.

Step-by-Step: Configuring ProxyJump

Let’s look at a practical scenario. We have three machines:

  1. Your Machine: Your local laptop.
  2. Bastion Host: Public IP 203.0.113.10 (User: jumpuser).
  3. Database Server: Private IP 10.0.0.50 (User: dbadmin).

1. The Quick One-Liner

Need a fast connection without editing files? Use the -J flag. It is the most direct way to hop into a private network.

ssh -J [email protected] [email protected]

This command encrypts your traffic end-to-end. The Bastion acts only as a relay. Unlike the old ‘Agent Forwarding’ method, your private keys never touch the Bastion’s memory, which protects you if the gateway is ever compromised.

2. The Pro Method: SSH Config

Repeating long IP addresses is tedious. Instead, define your infrastructure in ~/.ssh/config to use simple aliases.

# Open your config
nano ~/.ssh/config

Add these blocks to automate the jump:

# The Entry Gateway
Host bastion
    HostName 203.0.113.10
    User jumpuser
    IdentityFile ~/.ssh/id_ed25519_gateway

# The Private Database
Host db-prod
    HostName 10.0.0.50
    User dbadmin
    ProxyJump bastion

Now, getting into your database is a simple one-word command:

ssh db-prod

3. Handling Multiple Hops

If your architecture requires jumping through an external gateway and then a specific department VPC, you can chain multiple hosts using commas.

ssh -J user1@gate1,user2@gate2 target-user@internal-node

Hardening the Front Door

Since the Bastion is your primary entry point, you must lock it down. Update /etc/ssh/sshd_config on the Bastion with these settings:

# Kill password attempts
PasswordAuthentication no

# Disable GUI forwarding
X11Forwarding no

# Only allow your specific admin user
AllowUsers jumpuser

# Disconnect idle sessions after 5 minutes
ClientAliveInterval 300
ClientAliveCountMax 0

Always run sshd -t to check for syntax errors before you restart the service. I have locked myself out of remote data centers more than once by skipping that five-second validation step. ProxyJump isn’t just a convenience feature; it is a fundamental tool for managing secure, modern Linux environments.

Share: