
Opening database ports or admin panels to the public internet is how “quick access” turns into long nights. This SSH tunnel setup guide tutorial shows how to reach private services on your VPS (MySQL, Redis, phpMyAdmin, and internal dashboards) without exposing extra ports.
You’ll set up local and remote tunnels, tighten SSH, and add guardrails that prevent common mistakes.
The commands below use Ubuntu Server 24.04 LTS (common in 2026 hosting). They also work on Debian 12/13 and most AlmaLinux/Rocky installs, with small path differences.
If you want a clean box to practice on, a HostMyCode VPS is an easy way to spin up an isolated lab with full root access.
What you’ll build (and why tunnels beat public ports)
SSH tunneling forwards traffic through an authenticated, encrypted SSH session. Instead of publishing a service on 0.0.0.0:3306 (MySQL) or 0.0.0.0:6379 (Redis), you keep it bound to 127.0.0.1 on the server.
You then access it from your laptop only when you need it.
- Local forward: you connect to
localhoston your laptop, and SSH carries the traffic to the VPS. - Remote forward: a port on the VPS forwards back to your machine (useful for webhooks or quick review environments).
- Dynamic forward (SOCKS): your laptop uses the VPS as a proxy to reach private networks (powerful, and easy to misuse).
Operationally, tunnels save work. You expose fewer ports and maintain fewer firewall rules.
They also help you avoid the “why is Redis getting hammered?” moment later.
Prerequisites checklist (5 minutes)
- A VPS or dedicated server with SSH access (root or a sudo user).
- Your local machine: Linux/macOS terminal or Windows 11+ with OpenSSH.
- SSH keys (recommended) and the server’s public IP.
- Services you want to access are installed (MySQL/MariaDB, Redis, or a web panel).
If you haven’t set up SSH keys yet, follow this SSH key setup tutorial first.
It’s faster to do that now than to debug access issues after changing SSH settings.
Step 1: Confirm the service listens only on localhost (server-side)
Before you build a tunnel, confirm the service isn’t already exposed. On the VPS, run:
sudo ss -lntp
You want to see lines like:
LISTEN 0 4096 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=...,fd=...))
LISTEN 0 4096 127.0.0.1:6379 0.0.0.0:* users:(("redis-server",pid=...,fd=...))
If you see 0.0.0.0:3306 or [::]:3306, the service is reachable from the network.
Fix the bind address before you do anything else.
Bind MySQL/MariaDB to localhost
On Ubuntu/Debian, edit the server config (paths vary slightly by distro and version):
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Set:
bind-address = 127.0.0.1
Then restart and confirm it’s loopback-only:
sudo systemctl restart mysql
sudo ss -lntp | grep 3306
Bind Redis to localhost
sudo nano /etc/redis/redis.conf
Confirm you have:
bind 127.0.0.1 ::1
protected-mode yes
Restart and verify:
sudo systemctl restart redis-server
sudo ss -lntp | grep 6379
If you’re doing WordPress performance work and planning to use Redis, you’ll also want hit verification and safe PHP wiring.
See our Redis object cache setup tutorial for the application side.
Step 2: Lock SSH down so tunnels don’t widen your attack surface
Tunnels ride on top of SSH. If SSH is weak, the tunnel doesn’t help much.
- Disable password auth (keys only) once you’ve confirmed key login works.
- Limit who can log in with
AllowUsersorAllowGroups. - Keep SSH on port 22 unless you have a specific operational reason to change it; keys, allowlists, and rate limits do the real work.
OpenSSH config:
sudo nano /etc/ssh/sshd_config
Recommended baseline:
PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AllowUsers admin
Reload safely (this keeps active sessions alive):
sudo sshd -t && sudo systemctl reload ssh
For a tighter hardening path (allowlists, 2FA options, audit logs), use this SSH lockdown tutorial.
It pairs well with tunneling because it reduces brute-force noise quickly.
Step 3: Create a local SSH tunnel to MySQL (laptop → VPS)
This is the common case. You want to use a GUI (TablePlus, DBeaver, HeidiSQL) or the CLI client against a MySQL instance that only listens on the VPS’s loopback.
On your laptop:
ssh -N -L 13306:127.0.0.1:3306 admin@YOUR_VPS_IP
-Lcreates a local forward.13306is the local port on your laptop (any free high port works).127.0.0.1:3306is the destination as seen from the VPS.-Nmeans “no remote command”; SSH stays open just to carry traffic.
Then, from the same laptop (new terminal), connect through the tunnel:
mysql -h 127.0.0.1 -P 13306 -u youruser -p
GUI tools should use:
- Host:
127.0.0.1 - Port:
13306 - User/password: your MySQL credentials
Quick diagnostic if it fails
- Check the tunnel is listening locally:
ss -lntp | grep 13306(on your laptop). - Check MySQL is listening on the VPS loopback:
sudo ss -lntp | grep 3306(on the VPS). - Check SSH logs on the VPS:
sudo journalctl -u ssh --since "10 min ago".
Step 4: Create a local tunnel to Redis (and verify you’re not hitting the public net)
Redis should almost never be internet-facing. A tunnel gives you access for debugging or maintenance without turning Redis into a public target.
On your laptop:
ssh -N -L 16379:127.0.0.1:6379 admin@YOUR_VPS_IP
Test with redis-cli (install locally if needed):
redis-cli -h 127.0.0.1 -p 16379 PING
You should see:
PONG
If you get NOAUTH, that’s expected on secured Redis installs. Provide -a with the password or use ACL credentials.
Step 5: Tunnel a web admin panel safely (phpMyAdmin, Netdata, internal tools)
Admin UIs are convenient and frequently attacked. The safer pattern is straightforward.
Bind the panel to 127.0.0.1 on the VPS, then tunnel it from your machine.
Example: tunnel to a local-only web service on port 8080
Assume the VPS runs an admin UI bound to localhost: 127.0.0.1:8080. On your laptop:
ssh -N -L 18080:127.0.0.1:8080 admin@YOUR_VPS_IP
Open in your browser:
http://127.0.0.1:18080
This works well with monitoring tools too.
If you’re building a lightweight monitoring view, see our Netdata monitoring setup guide—it uses access patterns that combine cleanly with tunnels.
Step 6: Make tunnels repeatable with SSH config (no more long commands)
Once you’ve typed the same tunnel command a few times, move it into ~/.ssh/config on your laptop.
After that, you can use short host names instead of long commands.
nano ~/.ssh/config
Add:
Host hmc-vps
HostName YOUR_VPS_IP
User admin
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519
Host hmc-mysql-tunnel
HostName YOUR_VPS_IP
User admin
LocalForward 13306 127.0.0.1:3306
ServerAliveInterval 30
ExitOnForwardFailure yes
Host hmc-redis-tunnel
HostName YOUR_VPS_IP
User admin
LocalForward 16379 127.0.0.1:6379
ServerAliveInterval 30
ExitOnForwardFailure yes
Now bring up a tunnel with:
ssh -N hmc-mysql-tunnel
ExitOnForwardFailure yes is worth keeping. Without it, SSH can stay “connected” even though the forward never came up.
That failure mode wastes time because you end up debugging the wrong thing.
Step 7: Keep tunnels stable in the real world (autossh + systemd user service)
For occasional admin work, a manual tunnel is enough.
If you need persistent access (for example, a jump host workflow for a small team), use autossh. It brings the tunnel back after a network drop.
Install on your laptop (Linux example):
sudo apt-get update
sudo apt-get install -y autossh
Create a systemd user service so it starts on login:
mkdir -p ~/.config/systemd/user
nano ~/.config/systemd/user/hmc-mysql-tunnel.service
[Unit]
Description=HostMyCode MySQL SSH tunnel
After=network-online.target
[Service]
ExecStart=/usr/bin/autossh -M 0 -N \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ExitOnForwardFailure=yes \
-L 13306:127.0.0.1:3306 admin@YOUR_VPS_IP
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
Enable and start:
systemctl --user daemon-reload
systemctl --user enable --now hmc-mysql-tunnel.service
systemctl --user status hmc-mysql-tunnel.service
Team note: avoid “always-on” tunnels from unmanaged personal laptops.
If multiple people need access, run tunnels from a controlled admin workstation or a bastion/jump VPS with strict access rules.
Step 8: Remote forwarding (VPS port → your local machine) for temporary webhooks
Remote forwarding flips the direction. It helps when a provider must hit a temporary callback URL on your laptop, but you don’t want to expose your home IP.
The VPS becomes the stable address.
On your laptop, forward VPS port 19000 to your local 9000:
ssh -N -R 19000:127.0.0.1:9000 admin@YOUR_VPS_IP
Now hitting http://YOUR_VPS_IP:19000 (if allowed by firewall) reaches your local 127.0.0.1:9000.
Make remote forwards safer
- Prefer binding the remote forward to
127.0.0.1on the VPS, then access it from the VPS (or via a second hop) instead of making it public. - In
/etc/ssh/sshd_config, keepAllowTcpForwarding yesbut avoid enabling gateway ports unless you’ve mapped out the exposure.
If you need a permanent public endpoint, use a normal reverse proxy or deploy the app properly.
Remote forwards are best kept short-lived.
Step 9: Firewall stance—what to open (and what to keep closed)
SSH tunneling doesn’t replace firewalling. It helps you keep more things closed by default.
Recommended rule of thumb for a typical hosting VPS:
- Open:
22/tcp(SSH),80/tcpand443/tcp(web). - Keep closed to the internet: MySQL
3306, Redis6379, Memcached11211, internal dashboards.
If a rule change locks you out or breaks traffic, you’ll want a recovery plan.
Keep this firewall troubleshooting tutorial bookmarked for the day you need it.
Step 10: Tunneling in cPanel/WHM environments (practical patterns)
On cPanel servers, you’ll sometimes need internal access for diagnostics without turning services public.
The same tunnel approach works. Keep your changes minimal, and let cPanel manage what it manages.
- Use tunnels for temporary access to internal web tools bound to localhost.
- Keep WHM locked down with 2FA and restricted access.
If you administer WHM for clients or resellers, tighten logins first. Follow this cPanel 2FA setup guide to cut down credential-based incidents.
Common pitfalls (and how to avoid them)
- “I tunneled MySQL but my app still can’t connect.” A tunnel helps your admin access. If an app on another server needs the database, use private networking or a DB proxy.
- Port already in use on your laptop. Pick a different local port: use
23306instead of13306. - Slow or flaky connection. Add keepalives (
ServerAliveInterval 30) and consider working from a machine closer to the VPS region. - Tunnels opened to the world via remote forwards. Avoid
GatewayPorts yesunless you explicitly want public exposure.
Security checklist: “tunnels done right”
- Services bind to
127.0.0.1(or a private interface), not0.0.0.0. - SSH uses keys; password auth is off.
- SSH logins limited to named users/groups.
- Tunnels defined in
~/.ssh/configwithExitOnForwardFailure. - Firewall opens only what must be public (usually 22/80/443).
- For production operations, monitoring is in place to catch failed services early.
Summary: a safer way to administer hosting services
An SSH tunnel is a small habit that pays you back constantly. You get on-demand access to admin-only services, and you stop publishing “private” ports to the internet.
Keep services bound to localhost, make tunnels repeatable with SSH config, and harden SSH so the workflow stays tight.
If you want a server that’s predictable for this kind of work—static IP, full control, and enough headroom for staging and diagnostics—start with a HostMyCode VPS.
If you’d rather have the OS, updates, and baseline hardening handled with you, choose managed VPS hosting and keep your focus on the applications.
If you routinely access private services (databases, Redis, admin UIs), do it on infrastructure you control end-to-end. A HostMyCode VPS gives you the access you need for SSH tunnels, while managed VPS hosting fits better when you want help maintaining secure server defaults.
FAQ
Do I need to open MySQL or Redis ports in the firewall to use an SSH tunnel?
No. That’s the point. Keep the service bound to 127.0.0.1 on the VPS and open only SSH (and web ports if you host sites).
Is SSH tunneling safe enough for production administration?
Yes, if SSH is hardened (keys-only, limited users, monitored logs). It reduces your exposed surface compared to publishing admin services publicly.
Can multiple teammates use the same tunneled port?
Each teammate runs their own tunnel on their own machine. Avoid sharing a single always-on tunnel from an unmanaged laptop; use a controlled bastion host if needed.
Why does my GUI tool connect but queries are slow?
The tunnel adds encryption and an extra hop, so latency matters. If the VPS is far from you, consider a closer region or run admin tools from a workstation near the server.
What’s the safest way to keep a tunnel up 24/7?
Use autossh on a controlled admin box (or jump VPS), add keepalives, and restrict SSH access tightly. For anything public-facing, prefer a real service endpoint rather than a permanent remote forward.