Self-Hosting a Server on an Old Laptop
I turned an old HP G62 laptop (i3, 6GB RAM) into a home server running Ubuntu Server 22.04. It hosts my files, blocks ads for my network, and manages my Docker containers. Here’s what I learned.
Why Bother
Cloud storage costs money and someone else holds your data. A home server costs electricity and an old laptop you weren’t using anyway. I wanted to own my files, run my own services, and learn how infrastructure actually works. That last reason turned out to be the most valuable — this project taught me more about networking, security, and Linux administration than any course.
The Setup
Hardware: HP G62 laptop, dual drive (100GB SSD + 278GB HDD), connected to the router via ethernet. No monitor, no keyboard — headless after initial setup. Lid closed, tucked on a shelf.
OS: Ubuntu Server 22.04 LTS. No GUI — everything through SSH. A desktop environment would waste RAM on a machine nobody’s looking at.
Network: Static IP assigned via DHCP reservation on the router. Server on ethernet for stability, my main laptop on WiFi.
INTERNET
|
ROUTER (WiFi + Ethernet)
| \
(Ethernet) (WiFi)
| \
HP Server Main Laptop
192.168.x.10 (dynamic)
What’s Running
Everything in Docker, managed through Portainer:
- Nextcloud (MariaDB + Redis) — file storage and sync. My personal Dropbox.
- Pi-hole — network-wide ad blocking. Every device on my network gets cleaner browsing.
- Portainer — container management GUI. Easier than raw Docker commands for daily stuff.
- Uptime Kuma — monitors whether services are actually running.
- Syncthing — file sync between devices.
- Nginx — reverse proxy with HTTPS via Let’s Encrypt.
Security Hardening
This is the part most tutorials skip and the part that matters most:
- SSH key authentication only — password login disabled completely.
- Custom SSH port (not 22) to reduce noise from automated scanners.
- Fail2ban watching SSH logs — auto-bans IPs after failed attempts. (A good use case for process tricks if you want to monitor the ban list in real time.)
- UFW firewall — only the ports I need are open, everything else denied.
- Docker network isolation — containers can’t talk to each other unless I explicitly allow it.
- Security headers on Nginx — scored Grade A on security header tests.
Problems I Hit
CGNAT. My ISP uses carrier-grade NAT, which means I don’t have a real public IP. Port forwarding doesn’t work. I tried WireGuard first, then realized why it can’t work with CGNAT. Switched to Tailscale — it punches through NAT automatically using relay servers. Problem solved, and I understood the networking better for having failed first.
CDN blocks. Some package mirrors are blocked from Syria. Workaround: download packages on my main laptop (which has different network access), then SCP them to the server. Not elegant, but it works.
Lid close behavior. Laptops default to sleeping when you close the lid. Had to configure systemd to ignore the lid switch: edit /etc/systemd/logind.conf and set HandleLidSwitch=ignore.
What It Taught Me
This project is where I realized I’m not really a web developer or an ML researcher — I’m someone who thinks in infrastructure and systems. The satisfaction of having a reliable, secure, self-maintained server running 24/7 is different from anything I’ve felt building websites.
See Also
- How I Accidentally Became a DevOps Engineer — this project is what made me realize what I actually am
- Running LLMs Locally with Ollama — the next self-hosting rabbit hole after this one
- Open WebUI — giving those local models a proper interface
- WSL for Development — where most of my dev work happens before it hits the server
- Bash Process Tricks — useful for managing services and monitoring from the terminal