How I Built a Home Server That Was Always On
A 12-year-old Sony Vaio. One working RAM stick. A dead screen. No battery.
This was the server that ran my production backend.
I didn't set out to build infrastructure. I was trying to host a side project without paying for a cloud server. The Vaio was in the cupboard gathering dust. I figured: how hard could it be?
Phase 1: Getting It to Boot
The first challenge was the hardware itself. The screen showed nothing — total black. The flashlight test ruled out a dead backlight; the panel itself had failed. I hooked it up to the TV via HDMI just to see what I was doing.
Getting it to boot was its own puzzle. I swapped RAM sticks around until the HDD light finally flickered. Something was alive.
The Windows backup process was where the display gave up entirely. I transferred 7GB of old data over USB 2.0 — four hours staring at a progress bar. Then I wiped the drive and installed Ubuntu Server.
The display came back to life after Linux was installed. Make of that what you will.
Then the ISO wouldn't boot. Modern Ubuntu Server ISOs don't play nice with legacy BIOS. The USB would just give a blinking cursor. The fix: re-flash the drive with Rufus in DD Image Mode — writing raw binary instead of the default ISO method. That finally worked.
Phase 2: The Rate-Limit Wall
The first working deployment was a Node.js football tactical board, managed with PM2. I could SSH into it from across the house. That felt like enough.
Then the StockStash backend got rate-limited.
StockStash is an investment tracker with a Python backend that pulls from Yahoo Finance. The backend was hosted on Render. Render's shared IPs are well-known to commercial APIs — Yahoo Finance was blocking requests. Moving it to a residential IP fixed the problem entirely.
This is when the Vaio became a real server.
The Stack
The setup ran two services:
- Node.js (football tactical board) — managed by PM2 - tacticalboard.sarvaeshhh.com
- Python (StockStash backend) — containerized with Docker - stockstash-api.sarvaeshhh.com
PM2 handled process management and auto-restart for the Node app. Docker isolated the Python backend and let me enforce guardrails I wouldn't otherwise have bothered with on a home machine.
Two guardrails worth calling out. First, Docker log rotation — the Vaio had a 12-year-old hard drive, and unbounded logs would have filled it:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Second, Firebase credentials mounted as read-only. If a container was ever compromised, it could read the credentials but couldn't modify or delete them:
volumes:
- ./firebase-credentials.json:/app/credentials.json:ro
Secrets went to the server via SCP. Nothing sensitive lived in the repo.
Cloudflare Tunnels Instead of Port Forwarding
I didn't want to open ports on my router. Port forwarding is fine, but it exposes your home IP and requires router config I'd rather not touch. Cloudflare Zero Trust tunnels solve this cleanly: cloudflared runs as a daemon on the server, establishes an outbound connection to Cloudflare's network, and your service is reachable at a subdomain you control. No inbound ports.
Setup is mostly through the Cloudflare Zero Trust dashboard. Once you configure the tunnel, you install the daemon:
sudo cloudflared service install
From that point, the tunnel comes up automatically on every boot.
CI/CD from the Living Room
The server ran a self-hosted GitHub Actions runner. I pushed code from my laptop; the Vaio pulled, built, and deployed automatically. A Personal Access Token embedded in the Ubuntu Git config meant the daemon never stalled waiting for authentication.
One problem early on: GitHub Actions' shared queue introduced unpredictable delays for scheduled jobs. The StockStash backend sent emails at 9:30 AM — queue lag made that unreliable. I replaced the scheduled workflow with a local Linux cronjob that pinged the container directly:
30 9 * * * curl -s http://localhost:8000/send-email
Fired exactly on time, every time.
Making It Resilient
The Vaio's BIOS was locked — no Wake-on-AC option. If power cut, the server stayed off until I pressed the button. My workaround: make recovery manual but fast.
I hardcoded a static IP via Netplan so the address was always predictable:
network:
version: 2
ethernets:
eth0:
dhcp4: no
addresses: [192.168.1.150]
gateway4: 192.168.1.1
nameservers:
addresses: [1.1.1.1, 8.8.8.8]
Every daemon — PM2, Docker, cloudflared — was set to auto-start on boot. After a power cut, pressing the power button once brought everything back in under 60 seconds.
What This Actually Was
The Vaio ran two production services, a CI/CD pipeline, and a secure public tunnel — on hardware that cost nothing and drew maybe 15 watts. It wasn't impressive infrastructure by any enterprise standard. But it was mine, it was real, and it taught me more about how systems actually work than any managed service ever did.
If you have an old laptop in a cupboard: give it a new brain. Or just give it to me please.