Skip to content

Accessing internal services from a developer laptop

Internal services on the dev VM (Postgres, Redis, OTel collector, Kafka if reintroduced) bind only to the private interface and are firewalled from the public internet. Developer access goes through an SSH tunnel over port 22, reusing the same key-based authentication that protects the VM.

Picking the right pattern

Different tools and workflows want different tunnel patterns. The right default depends on whether your tool can manage its own tunnel.

Pattern When to use Lifecycle
Tool-managed (pgAdmin / RedisInsight built-in tunnel) GUI tools that support SSH tunnels natively Opens on Connect, closes on Disconnect
Ad-hoc background tunnel (ssh -fN) Terminal tools like psql, redis-cli Foreground until you kill it
LocalForward in ~/.ssh/config You SSH into the VM regularly and want tunnels as a free side effect Lifetime of the SSH session
autossh "Always on" tunnels for multiple tools Persistent, auto-reconnects

The recommended default for GUI tools is tool-managed. It doesn't require an open SSH session in another terminal, has the same lifetime as your DB connection, and survives laptop sleep / network changes because the tool just re-opens the tunnel on its next connect.

Add Server → fill three tabs:

General - Name: dev

Connection - Host: 127.0.0.1 - Port: 5432 - Maintenance DB / Username / Password: per your dev credentials

SSH Tunnel - Use SSH tunneling: on - Tunnel host: dev.grintest.pl - Tunnel port: 22 - Username: filip - Authentication: Identity file~/.ssh/grintest_hetzner_dev - Identity file passphrase: leave empty if your key is unlocked via ssh-agent / macOS Keychain.

pgAdmin opens the tunnel when you click Connect and closes it when you disconnect from the server. No background process to manage.

When adding the dev connection:

  • Database alias: dev
  • Host: 127.0.0.1
  • Port: 6379
  • Tick Use SSH Tunnel:
  • SSH host: dev.grintest.pl
  • SSH port: 22
  • SSH username: filip
  • Auth: Private Key → upload ~/.ssh/grintest_hetzner_dev

Same lifecycle as pgAdmin: opens on Connect, closes on Disconnect.

3. Terminal tools — ad-hoc background tunnel

For psql, redis-cli, pgcli, etc. — anything without built-in SSH support — start a background tunnel for the duration of your work:

# Postgres
ssh -fNL 5432:localhost:5432 dev.grintest.pl

# Redis
ssh -fNL 6379:localhost:6379 dev.grintest.pl

-f backgrounds the SSH process, -N skips command execution. Now any local tool sees the dev services on localhost:

psql -h 127.0.0.1 -U <user> <db>
redis-cli -h 127.0.0.1

Kill the tunnels when done:

pkill -f 'ssh -fNL 5432'
pkill -f 'ssh -fNL 6379'

4. LocalForward in ~/.ssh/config (optional)

If you SSH into the dev VM regularly anyway, you can fold the tunnels into your SSH config so they open automatically whenever you start an SSH session:

Host dev.grintest.pl
    User filip
    IdentityFile ~/.ssh/grintest_hetzner_dev
    IdentitiesOnly yes
    LocalForward 5432 127.0.0.1:5432
    LocalForward 6379 127.0.0.1:6379

The tunnels live for the lifetime of the SSH session — close the terminal and they're gone. Worth it only if "I always have a shell open to dev" is your reality.

5. autossh for persistent tunnels (advanced)

If you want tunnels that survive laptop sleep, Wi-Fi changes, and intermittent VM restarts without thinking about it, install autossh:

brew install autossh

autossh -M 0 -f -N \
    -o "ServerAliveInterval 30" \
    -o "ServerAliveCountMax 3" \
    -L 5432:localhost:5432 \
    -L 6379:localhost:6379 \
    dev.grintest.pl

autossh monitors the SSH connection and auto-reconnects on failure. Wrap it in a launchd plist (macOS) or systemd --user unit (Linux) to start on login.

This is overkill for casual use but a worthwhile setup if multiple GUI tools are hitting localhost simultaneously and you want one tunnel shared between them.

What this gives you

  • Zero new firewall holes — port 22 is the only public ingress, and you already trust it for SSH.
  • Same key-based authentication as your regular shell access; passphrase unlocked once per session by ssh-agent / Keychain.
  • Tools see localhost connections, so connection strings stay portable between laptop and CI without secret rewriting.

What this is not

  • Not a production access pattern. Production access goes through separate audit-logged channels (TBD when prod lands).
  • Not a substitute for least-privilege DB users. Tunnel access still authenticates against whatever Postgres role you log in as — keep those scoped.