003 / project
Home infrastructure
A small home lab: Linux, Docker, and a private network, kept to a size I can still explain.
Personal learning build. These notes describe a design. They are not production metrics, client work, or a claim about users.
Context
I wanted a place to run small services and to understand the network they sit on. Not a pretend datacenter. A machine at home, in Madrid, with a path to reach it that does not mean publishing the house.
The lab is personal infrastructure. It is not a client environment, and it does not have a traffic number worth quoting. The useful output is a picture of how a request gets in, and how the data gets back if the disk misbehaves.
Constraints
One Linux host, or a very small number of them. If the diagram needs a cluster, the diagram is wrong.
Docker is a process boundary, not an identity. A container does not excuse a service that binds the wrong interface.
Remote access goes through a private network. Opening a port on the home router is the design I am refusing.
Backups are part of the system. A copy I have never restored is a rumor.
Services have to earn their place. The ops tax of self-hosting is real, and I only want to pay it for things I actually use.
Architecture
The picture is a path, not a platform.
- 01Laptop or phoneJoins a private network. It does not need an open port at home.
- 02TailscaleThe path in. Port-forwarding the router is the option I am not taking.
- 03Linux hostOne machine, still small enough to explain.
- 04DockerA process boundary per service. Compose files stay separate.
- 05Internal proxyNames inside the network. Not a public front door.
- 06DiskThe data worth keeping, and a restore that has to be real.
A laptop or a phone joins the tailnet. Tailscale is the way in. The Linux host runs a handful of containers. An internal proxy gives them names on that network. The disk holds the data that would hurt to lose. Nothing in that path requires the router to forward a public port.
Decisions
Tailscale instead of a hand-punched hole in the router. I know that makes Tailscale a dependency. Hand-rolled WireGuard would teach the packets more directly, and it would also fail in more interesting ways at eleven at night. I want the private path first. I can still read what it replaced.
Compose files stay per service, not one stack that boots the entire house. A failure should take down the thing that failed.
Bind mounts for data I care about, so I can see the files without asking a volume driver to explain itself. Anonymous volumes are fine for data I am willing to treat as cache.
The proxy is internal. Names and certificates exist so I can remember where a service lives. They are not a public website with a marketing domain.
Updates are manual and boring. Automatic upgrades are a fine way to discover a breaking change when I am not at the machine.
Data flow
I open a client that is on the tailnet. DNS for the service name resolves inside that network, not on the public internet. The connection reaches the host. The proxy routes by name to the container. The container talks to its files on a mount, or to another container on a network I created on purpose.
From the outside, the house looks like a house. There is no published map of ports. From the inside, every service I use has a name I chose and a place on disk I can find.
Tradeoffs
Docker is convenient, and it is also a place to hide a networking mistake. A container can bind 0.0.0.0 and feel private because I forgot it was attached to a network that is not. The interface and the Docker network are part of the design, not an accident of the defaults.
Tailscale is simpler than running my own coordination server, and it means I trust that coordination. I accept the trade for a home lab. I would not describe it as "no trust." I would describe it as a trust I can name.
Self-hosting has an ops tax that a hosted service does not. I only want services whose absence I would notice, and whose data I am willing to be responsible for.
One host is a single point of failure. For this lab, that is acceptable. Pretending otherwise would mean building a cluster in order to feel serious.
Problems
DNS is the first place the picture lies. A name that works on the tailnet and a name that works on the home LAN are not automatically the same name. I would rather have one name that works on the path I actually use than two names that work in different rooms.
Containers that publish every port to the host are the second lie. Publishing is a decision. The default in a compose file should be "not published," and the exception should be visible.
Backups that I have not restored are the third. Copying files to another disk feels like safety. It is a plan. The test is deleting something small on purpose and getting it back.
Updates drift. A host you do not patch becomes a different system from the one you drew. The drawing has to be cheap to revisit, or it becomes fiction.
What I learned
The network is the architecture. The containers are details inside it.
A service without a way to reach it, and a way to get the data back, is a demo that happens to be running.
Small is a feature. The moment the diagram needs a legend, I have probably added a box I do not use.
Next iteration
Write the restore down as a sequence I can follow without remembering it. Then keep a scratch corner, for things I am willing to break, separate from the disk that holds data I am not.