Hardening configs, tunneling architectures, proxy chains, jump hosts, multiplexing, and intrusion prevention — all hands-on in a simulated environment.
sshd_config ships with root login enabled and password
authentication allowed on port 22. You need to harden it before the server
goes live.
The current config is shown below. Use the terminal to apply each hardening directive. After all three changes, click Apply & Diff to see the before/after.
Type each hardening command below. Run them in order:
sudo sed -i to edit in place, or type the exact directive.
For step 1: sudo sed -i 's/^Port 22/Port 2222/' /etc/ssh/sshd_config
Changing the default port is security-by-obscurity, but it eliminates 95 % of automated SSH scanners. Disabling root login forces attackers to know a valid username first. Disabling password auth makes brute-force attacks impossible — only key holders can connect.
Always run sudo sshd -t (test mode) before restarting the daemon.
A syntax error in sshd_config will lock you out of the server completely.
localhost:3000. Your manager is on a remote machine at
jump.hexworth.io and wants to review it. You need to expose your
local server through the jump host so they can hit
http://jump.hexworth.io:9090.
Type the command that creates the reverse tunnel:
-R remote_port:local_host:local_portssh -R 9090:localhost:3000 student@jump.hexworth.io
-R 9090:localhost:3000 tells the remote host to listen on port
9090 and forward incoming connections back through the SSH tunnel to your
localhost:3000. The format is always
-R [remote_bind:]remote_port:local_host:local_port.
By default the remote port binds only to 127.0.0.1 on the jump
host. To allow external connections, the remote sshd needs
GatewayPorts yes (or clientspecified) in its
sshd_config. Without that, the manager cannot reach port 9090 from outside the
jump host itself.
192.168.10.0/24 subnet through a remote server that has access.
Instead of a static port forward per service, you will create a
dynamic SOCKS5 proxy so all browser traffic routes through the SSH host.
Step 1: Open the SOCKS proxy tunnel on local port 1080.
-D port opens the SOCKS listener locally.-N = no remote command (tunnel only). -f = go to background.ssh -D 1080 -N -f student@relay.hexworth.io
Step 2: Configure Firefox to use the proxy.
A SOCKS proxy routes application-layer TCP/UDP traffic on a per-app basis. A VPN creates a virtual network interface and routes all system traffic at the OS level. Use SOCKS when you only want one application (e.g. browser) to go through the tunnel. Use VPN when you need the entire machine's traffic routed remotely.
Without "Proxy DNS" checked, Firefox resolves DNS locally even though HTTP traffic goes through the tunnel. Your ISP sees every domain you visit. Always enable remote DNS resolution when privacy is the goal.
web-01,
db-01) are not exposed to the internet. Only a bastion host
(bastion.hexworth.io) is publicly reachable. You need to SSH
directly to web-01 without manually logging into the bastion first.
Type the one-liner to reach web-01 via the bastion:
-J jumphost is the ProxyJump flag. Syntax:ssh -J user@jumphost user@destinationssh -J student@bastion.hexworth.io student@10.0.0.5
To make this permanent, add it to ~/.ssh/config:
Bastion hosts reduce your attack surface from N servers to 1. The bastion receives all scrutiny: intrusion detection, enhanced logging, MFA, and strict firewall rules. Internal servers only accept connections from the bastion's IP, so even if an internal server is vulnerable, it cannot be reached directly from the internet.
ForwardAgent yes lets the bastion use your local SSH keys to
hop further. Convenient — but if the bastion is compromised, an attacker can
use your forwarded agent to authenticate as you on other hosts. Use
ForwardAgent only on trusted bastions, or prefer ProxyJump (which
does not expose your agent).
Add multiplexing directives to ~/.ssh/config:
ssh -O check deploy.hexworth.io — check master socket statusssh -O exit deploy.hexworth.io — cleanly close mastergrep ControlMaster ~/.ssh/config — verify config
The complete ~/.ssh/config block for multiplexing:
Simulated benchmark — first connection vs multiplexed:
auto — use existing master if available, otherwise become the master.
yes — always become the master (fails if already exists).
no — never multiplex (always fresh connection).
autoask — ask before reusing (useful in interactive sessions).
Multiplexing is ideal for: CI/CD pipelines, Ansible/Salt deployments, repeated
git operations over SSH, and interactive sessions where you open many panes to the
same server. ControlPersist 10m keeps the master alive 10 minutes
after the last session closes, so rapid reconnects are still fast.
Install fail2ban and check its status:
sudo apt install fail2ban -ysudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localsudo fail2ban-client status sshdsimulate attack — trigger the brute-force simulationsudo fail2ban-client status sshd — check bans
Your /etc/fail2ban/jail.local SSH section:
Fail2Ban tails log files (auth.log, syslog) and matches lines against
regex filters. When an IP hits maxretry failures within
findtime seconds, fail2ban inserts an iptables/nftables DROP rule
for that IP for bantime seconds. No credentials are ever exposed —
the attacker's packets are silently dropped at the kernel level.
Set bantime = -1 for permanent bans (recidive jail).
Add your admin IPs to ignoreip or you risk locking yourself out
if you mistype your password. For cloud servers, combine fail2ban with
cloud-level security groups to block at the network edge before traffic
even reaches the OS.
Complete all six exercises to unlock lab completion credit.