The door that does not answer

Putting your server in your pocket, without opening it to the internet

I wanted to drive an agent running on my server from my phone. The obvious answer — a subdomain and a password — was the wrong one, for a reason that has nothing to do with cryptography. Here is the reasoning, and the three silly traps that cost me an afternoon.

What you are really exposing

An agent running as a server is not a web page. It is a command interpreter. It reads files, writes files, runs programs. Putting that behind a subdomain with a password means putting a shell on the internet and hoping the password holds.

The right question is not "is my password strong". It is: what does someone get if they walk through this door? On an agent server the answer is almost always: everything. The account running the agent is the one allowed to deploy, restart, read configuration. Assume whoever reaches it becomes administrator, and your reasoning will be sound.

The rule I draw from it. What is public is what must be: a site, an API. A control tool has no reason to be reachable by a stranger — even a protected one. You do not harden a needless door: you remove it.

Why not an off-the-shelf service

Services exist that set up this kind of tunnel in three clicks. They all rest on the same proven encryption, and I have nothing against them on that front.

The weak point is elsewhere. These services run a coordination server: a machine, on their side, that knows which devices exist and hands out authorisations. It is not the tunnel an attacker aims at, it is that directory. And when it falls, it falls for everyone at once.

Build the tunnel yourself and that directory does not exist. Machines recognise each other by their key, exchanged once, by hand. There is nobody to compromise, because there is nobody.

A door that does not answer

Here is the property that decides everything, and it is poorly understood.

An SSH server open to the internet answers. Send it anything and it announces its name and version. That is how you end up on a list: robots sweep the internet constantly, note what answers, and come back later.

The tunnel does not answer. A packet not signed by a key it already knows is dropped without a word: no refusal, no error, nothing. To a sweeping robot, that port does not exist.

Do not confuse this with hiding. Moving a service to an unusual port hides it: whoever looks properly finds it. Not answering is something else — even knowing exactly where to knock, you get nothing without the key. Obscurity is not security; here it is the consequence, not the method.

A pleasant consequence: once the tunnel is up, you can close the usual administration access. You are not adding a door, you are replacing a talkative one with a silent one.

The three traps

The tunnel worked first try. It was everything else that fought back, and none of the three problems was interesting. Here they are, so they do not cost you the same afternoon.

1. Packet size

Symptom: small responses go through, large ones vanish. A page that "loads" forever, no error, no log entry. It is the worst kind to diagnose, because something works.

A tunnel wraps an envelope around every packet. If the configured value ignores that envelope, full packets are silently dropped somewhere along the path — while a short round trip sails through. I suspected authentication, server configuration, a bug in the software. It was a matter of size.

The test that settles it. Compare an empty response with one that has content. If the empty one arrives and the other does not, stop looking at the software: it is the size. Drop the value to 1280, the safest, mobile networks included.

2. The invisible space

A rejected key, an error message about length. The key was right — checked on both sides, same fingerprint. The phone keyboard had added a trailing space to the paste.

An hour lost suspecting a correct key. When a pasted secret is rejected, the first hypothesis is not that it is wrong: it is that it was damaged in transit.

3. The address in the wrong field

The form asks for two addresses that have nothing to do with each other: yours inside the tunnel, and the server's, to reach it. Put the second where the first belongs and the tunnel still establishes — the handshake does not depend on it — but nothing flows afterwards. It half works, which is the worst way of not working.

The guard that erases

Last episode, and the most instructive. Twice, the tunnel went quiet on its own after working.

My firewall is not configured by hand: it is declared in a file, and a program reapplies it on a schedule. Any rule added on the side disappears at the next pass. Without a message, of course: it is not correcting a mistake, it is restoring the intended state.

What makes the symptom deceptive is that the connection already open survives. Everything looks fine — until the first interruption, when nothing comes back.

Not a bug, the feature. A firewall edited by hand drifts, and nobody remembers why a given port is open. Declared, it can be read back. The right reaction was not to re-add my rule: it was to write it into the file, with the comment explaining why it exists. A rule without its reason will be deleted by the next person tidying up — and they will be right.

What I am not writing here

An article about your own infrastructure means deciding what to leave out. My rule: no values. No key, no password, no machine address, no port number. Not because knowing them would be dangerous — a system's strength must never rest on the secrecy of its mechanics — but because they are useless to the reader. What helps them is the reasoning; what does not help them but would help someone else, you keep.

There is also what I leave out because it is not settled. An agent server reachable through the tunnel grants access to a powerful account, and that is the real subject — more important than the whole tunnel debate. The tunnel is the easy half.

What I take away. Security was not decided by the choice of encryption — that was a given. It was decided by three boring calls: do not expose what does not need exposing, depend on nobody to distribute trust, and write your rules where a program reads them back. The rest is trailing spaces.
🔭