Put Self Hosting On Your Cv
Put Self Hosting On Your Cv
Introduction
In today’s competitive DevOps landscape, simply listing “Docker” or “Kubernetes” on a résumé is no longer enough. Recruiters and hiring managers are increasingly looking for concrete evidence that a candidate can design, deploy, and maintain end‑to‑end self‑hosted environments. The ability to spin up a reliable homelab, automate deployments, manage secrets, and harden security demonstrates a depth of operational knowledge that cannot be faked through certifications alone.
The Reddit discussion that sparked this guide highlighted a simple truth: a well‑documented self‑hosted setup on a curriculum vitae signals that the author has wrestled with the “boring” yet critical aspects of system engineering — monitoring, logging, version control, CI/CD pipelines, and security hardening — while also delivering measurable uptime. For senior‑level roles, this hands‑on experience often outweighs theoretical knowledge.
This comprehensive guide walks you through the entire lifecycle of building a production‑grade self‑hosted stack that you can proudly showcase on your CV. We will cover:
- The core concepts behind self‑hosted infrastructure and why they matter to employers.
- Prerequisites, installation steps, and configuration best practices for a typical stack (Docker, Docker‑Compose, Prometheus, Grafana, and a lightweight Git‑server).
- Security hardening, performance tuning, and scaling considerations.
- Real‑world troubleshooting techniques and maintenance routines.
By the end of this article, you will have a reproducible, documented environment that you can reference in your résumé, LinkedIn profile, or personal portfolio. You will also understand how to articulate the value of each component to non‑technical hiring managers, turning a hobby project into a compelling career asset.
Keywords: self‑hosted, homelab, DevOps, infrastructure automation, open‑source, container orchestration, monitoring, security, CI/CD, GitOps.
Understanding the Topic
What Is a Self‑Hosted Stack?
A self‑hosted stack refers to a collection of services — such as web applications, databases, monitoring tools, and version‑control repositories — that you install, configure, and operate on hardware or virtual machines you control. Unlike SaaS alternatives, self‑hosted solutions give you full ownership of the runtime environment, allowing you to customize networking, storage, and security policies to meet exacting operational requirements.
Historical Context
The concept of self‑hosting dates back to the early 2000s when sysadmins began running their own mail, web, and file servers on dedicated boxes. With the advent of containerization, the paradigm shifted: developers could now package entire applications into lightweight, portable images that run consistently across environments. Docker, introduced in 2013, popularized this approach, and Docker‑Compose soon after enabled multi‑container orchestration on a single host.
Core Features and Capabilities
- Isolation – Containers provide process‑level isolation, ensuring that one service’s failure does not cascade to others.
- Reproducibility – Infrastructure as Code (IaC) manifests (Dockerfiles, docker‑compose.yml) allow you to recreate the exact same environment on any machine.
- Version Control – All configuration files can be stored in Git, enabling rollbacks and collaborative development.
- Automation – Scripts and CI pipelines can automatically build, test, and deploy updates without manual intervention.
- Observability – Integration with Prometheus, Grafana, and Loki provides real‑time metrics, dashboards, and logs.
Pros and Cons
| Advantages | Challenges |
|---|---|
| Full control over upgrades, patches, and configuration | Requires disciplined operational hygiene |
| Ability to tailor performance and security settings | Resource constraints on low‑end hardware |
| Demonstrates end‑to‑end DevOps skills | Learning curve for advanced networking and storage |
| Open‑source ecosystem offers abundant tooling | Maintenance overhead if not automated |
Use Cases and Scenarios
- Personal Homelab – Experimentation with new technologies, learning, and hobby projects.
- Development Environments – Providing developers with identical local stacks that mirror production.
- Edge Computing – Deploying lightweight services on edge devices with constrained resources.
- Small‑Scale Production – Hosting internal tools (e.g., issue trackers, CI runners) for teams of 5‑20 engineers.
Current State and Future Trends
The self‑hosted movement continues to mature, with projects like Kubernetes offering production‑grade orchestration for those ready to scale beyond a single host. However, for many DevOps professionals, a well‑designed Docker‑Compose stack remains the sweet spot: it offers sufficient depth to showcase operational expertise without the overhead of managing a full‑blown cluster. Emerging trends include GitOps pipelines, infrastructure‑as‑code with Terraform, and zero‑trust networking models that further harden self‑hosted deployments.
Comparison to Alternatives
| Solution | Typical Use‑Case | Complexity | CV Impact |
|---|---|---|---|
| SaaS (e.g., GitHub, GitLab.com) | Simple code hosting | Low | Minimal – indicates usage only |
| Managed Kubernetes (EKS, GKE) | Large‑scale production | High | Moderate – shows cloud expertise |
| Self‑Hosted Docker‑Compose + Prometheus/Grafana | Homelab, internal tools | Medium | High – demonstrates full lifecycle ownership |
Prerequisites
Before embarking on the installation, ensure your environment meets the following baseline requirements.
| Requirement | Minimum Specification | Recommended |
|---|---|---|
| Hardware | 4 CPU cores, 8 GB RAM, 100 GB SSD | 8 CPU cores, 16 GB RAM, 250 GB SSD |
| Operating System | Ubuntu 22.04 LTS or Debian 12 | CentOS 9 Stream or Rocky 9 |
| Docker Engine | Docker 24.0.x | Docker 24.0.x with BuildKit enabled |
| Docker‑Compose | Docker‑Compose 2.20.x | Docker‑Compose 2.23.x |
| Network | Static IP or Dynamic DNS for external access | Gigabit Ethernet, port‑forwarding enabled |
| User Permissions | sudo access for initial setup | Dedicated docker group membership |
| Security | OpenSSH 9.0+ | UFW or firewalld with default deny inbound |
Pre‑Installation Checklist
- Update the OS packages:
sudo apt update && sudo apt upgrade -y. - Install prerequisite packages:
sudo apt install -y curl git ufw. - Configure a non‑root user with sudo privileges and add to the
dockergroup:sudo usermod -aG docker $USER. - Verify Docker daemon status:
systemctl status docker. - Open required ports (e.g., 80, 443, 3000) in the firewall:
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp && sudo ufw allow 3000/tcp && sudo ufw enable.
External resources:
- Docker Engine installation guide – https://docs.docker.com/engine/install/
- Official Docker‑Compose documentation – https://docs.docker.com/compose/install/
Installation & Setup
The following sections walk you through a reproducible installation of a minimal self‑hosted stack that includes a Git‑server (Gitea), a Prometheus monitoring stack, and a Grafana dashboard. All components are defined in declarative configuration files, ensuring repeatability.
1. Directory Structure
Create a dedicated directory for the stack and organize files as follows:
1
2
3
4
5
6
7
8
9
10
11
selfhost/
├── docker-compose.yml
├── gitea/
│ ├── app/
│ └── conf/
├── prometheus/
│ └── prometheus.yml
└── grafana/
└── provisioning/
└── dashboards/
└── dashboard.yaml
This layout separates each service’s data, configuration, and provisioning artifacts, making it easy to version‑control and back up.
2. Docker‑Compose Manifest
Below is a complete docker-compose.yml that defines the three services. Notice the use of environment variables and volume mappings that persist data across container restarts.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
version: "3.9"
services:
gitea:
image: gitea/gitea:1.23
container_name: $CONTAINER_NAMES_gitea
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__INSTALL_LOCK=1
volumes:
- ./gitea/app:/data/app
- ./gitea/conflogs:/data/log
- ./gitea/conf:/etc/gitea
ports:
- "3000:3000"
- "22:22"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
prometheus:
image: prom/prometheus:v2.51
container_name: $CONTAINER_NAMES_prometheus
restart: unless-stopped
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
ports:
- "9090:9090"
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
- "--web.enable-admin-api"
grafana:
image: grafana/grafana:10.4
container_name: $CONTAINER_NAMES_grafana
restart: unless-stopped
ports:
- "3001:3000"
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
environment:
- GF_SECURITY_ADMIN_PASSWORD=$GRAFANA_ADMIN_PASSWORD
volumes:
prometheus_data:
grafana_data:
Explanation of Key Sections
container_name– Uses the$CONTAINER_NAMES_*placeholder to maintain consistency with Jekyll‑compatible templating.restart: unless-stopped– Guarantees automatic recovery after host reboots.- Healthcheck – Periodically validates that Gitea is reachable, providing early detection of failures.
- Volumes – Persist application data (
app,log,conf) and metrics (prometheus_data,grafana_data). - Ports – Map host ports to container ports for external access.
To launch the stack, execute:
1
2
cd selfhost
docker compose up -d
Verify container status:
1
docker ps --filter "name=$CONTAINER_NAMES_"
3. Configuration Files
Gitea Configuration (gitea/conf/app.ini)