Asaduzzaman Pavel

The Evolution of My Remote Workflow: From SSH Spaghetti to a Streamlined Setup

For a long time, my relationship with remote servers was… messy. As a Backend Engineer, I’m constantly jumping between dev environments, staging clusters, and production databases. But for the longest time, my “workflow” was just a series of Ctrl+R searches in my shell history, hoping to find that one specific IP address or long-forgotten identity file flag.

It was “SSH Spaghetti.” It worked, but it was friction-heavy. This is the story of how I moved past that chaos and turned my ~/.ssh/config into a core part of my engineering identity.

The Breaking Point: The “Two-Step” Dance

The moment I realized I needed a better way was when our team moved behind a Bastion host (Jump Box). Suddenly, every time I wanted to check a log or run a quick query on an internal DB, I had to:

  1. SSH into the Bastion.
  2. Authenticate again.
  3. SSH from the Bastion to the internal server.
  4. Copy-paste data back and forth like a digital courier.

It was exhausting. It broke my flow. I started avoiding small tasks because the “setup cost” of just getting into the server was too high. That’s when I started looking for a way to make the infrastructure transparent.

Discovery: The Hidden “Engine”

I had always known the ~/.ssh/config file existed for simple aliases (e.g., Host dev), but I didn’t realize it was a full-blown configuration engine.

Solving the Bastion Headache

When I discovered ProxyJump, it felt like magic. I could define my Bastion and my internal servers once, and suddenly I was back to a single command: ssh internal-db. SSH was handling the tunneling, the identity forwarding, and the multi-hop authentication behind the scenes.

The friction was gone. I wasn’t “logging into two boxes” anymore; I was just “going to work.”

The “Aha!” Moment: Instant Connections

The second major shift in my journey was discovering Multiplexing (via ControlMaster).

As someone who often has three terminal windows open for the same server—one for htop, one for logs, and one for a shell—I was used to the 2-3 second delay of the SSH handshake every time I opened a new tab. It doesn’t sound like much, but multiplied by 50 times a day, it adds up to a lot of “micro-waiting.”

Setting up a socket-based connection reuse changed everything. The first connection took its usual time, but the second and third were instantaneous. It made the remote server feel like it was running locally on my machine.

The Refinement: Integration with My NixOS/Dotfiles

As I went deeper into the NixOS ecosystem (which I’ve written about before), my SSH config stopped being a static file and started being a “living document.”

I began version-controlling it in my private dotfiles repo. I added global defaults like ServerAliveInterval to stop those annoying “Broken Pipe” disconnects during my morning coffee breaks. I set up AddKeysToAgent so I only had to type my long, complex passphrase once per reboot.

My SSH config became an extension of my NixOS philosophy: Reproducible, reliable, and frictionless.

Why It Matters

We often focus on the “big” tools—the frameworks, the languages, the databases. But as engineers, we live in the “small” tools. The way we move between servers is the “commute” of our workday.

By taking the time to refine my SSH config, I didn’t just save a few seconds here and there; I removed the mental overhead of “getting there.” Now, whether I’m jumping through a triple-bastion setup or just checking a dev box, the experience is identical. Mastering the small tools makes the big work easier.

My Current Philosophy

StageMy Old Way (Spaghetti)My New Way (Refined)
Identity-i ~/.ssh/key_nameAutomatic per-host IdentityFile
JumpingManual two-step SSHTransparent ProxyJump
Speed3-second handshakesInstant Multiplexing
PersistenceFrequent “Broken Pipes”ServerAlive Keep-alives