Homelab — Cameron Miller

Virtualization / Linux / Networking / Self-hosting

Learning by running my own infrastructure

My homelab is where I put networking and systems concepts into practice. Built around Proxmox VE, it gives me a place to work with virtualized Linux servers, deploy services, and troubleshoot the connections between them. Hosting this website is one of the projects that has brought those pieces together.

The most useful part has been following a problem across multiple layers: a service can be running correctly while a DNS record, firewall rule, or container connection still prevents anyone from reaching it. Working through those problems has helped me understand how infrastructure supports an application.

The tools I work with

Proxmox VE & Ubuntu Server
Proxmox is the foundation of my lab, with virtualized Linux servers providing environments for services and experiments. Working with Ubuntu Server has given me hands-on experience with Linux administration, SSH access, service configuration, and troubleshooting.
Docker & Portainer
I use containers and container management tools as part of my self-hosted environment. Docker networking has been a practical lesson in how services discover and reach each other, and why an application's listening port and the port exposed on its host are different pieces of the connection.
Nginx Proxy Manager, DNS & HTTPS
My website runs behind Nginx Proxy Manager with HTTPS enabled. Connecting the domain to the reverse proxy and the application helped me understand the difference between resolving a name, forwarding a request, and serving the application itself.
Tailscale, SSH & UFW
These tools are part of my work with remote access and host security. They have helped me think about which services need to be reachable, how I administer servers, and how firewall rules affect connectivity.

From a browser request to a database entry

Getting cam1ller.com working gave me a concrete example of how a web service fits into a network. DNS resolves the domain first; the web request then reaches the reverse proxy, which forwards it to the application server.

Gunicorn serves the Flask application. Flask handles the site's routes and API requests, while SQLite stores the Daily Log entries. The private admin interface lets me create, edit, and delete posts that appear on the public site.

Building that workflow gave me experience with REST API endpoints, persistent storage, password verification, session-based authentication, and CSRF protection for administrative changes. It also showed me why application logic and deployment configuration both matter to a working service.

Networking lessons from the lab

DNS resolution and service reachability are separate checks

A domain resolving to an address does not guarantee that the website is available. The destination still needs a reachable port, an allowed network path, a correctly configured proxy, and a working application. Separating these checks makes troubleshooting much more focused.

Every connection has an address, a port, and a network context

Working through Docker communication problems made this especially clear. Inside a container, localhost refers to that container. Reaching another service depends on the networks they share and the address and port used for the connection. Host port mappings and container ports need to be understood separately.

A reverse proxy connects the public site to its backend

The proxy receives web traffic and forwards requests to the configured upstream service. HTTPS adds certificate and TLS configuration to that path. If the upstream address or port is wrong, the public-facing proxy can be reachable even though the application behind it is unavailable.

Remote administration and public access serve different purposes

Working with Tailscale, SSH, and UFW has helped me distinguish management access from visitor traffic. A public website needs to be reachable by its audience; administrative services need access appropriate to their purpose. Firewall rules are part of that design, as well as a common place to investigate connection failures.

How I approach troubleshooting

My biggest takeaway is to trace the connection in stages and use each result to narrow the next check. For a self-hosted website, that means asking:

  1. Name resolution: Does the domain resolve to the intended destination?
  2. Network access: Can the client reach the required port, and do the relevant firewall rules allow it?
  3. Proxy configuration: Does the request reach the correct upstream address and port?
  4. Application health: Is the service listening where expected, and what do its logs show?
  5. Data and behavior: Can the application read and save its data, and do authenticated actions work as intended?

What I’m taking forward

This lab has helped me connect virtualization, Linux administration, networking, and software development through a project I actually operate. Getting the website and Daily Log working was a milestone; continuing to clean up the environment and build out the site gives me more opportunities to practice.

I keep updates in my Daily Log. My projects page also includes a Python port scanner and network discovery tool, extending my interest in understanding how hosts and services communicate.