Initialize Your Cloud Ops Homelab Repo
Set up a professional GitHub repo with CI, ADRs, and engineering standards.
Introduction
30 Second Summary
Every engineering team you will ever join has one thing in common. Their best work starts with structure, documentation, and clear intent before a single feature gets built.
In this project, you will create a professionally structured GitHub repository for a Cloud DevOps homelab. You will configure Git with SSH authentication, establish engineering documentation standards, set up automated CI, and tag your first versioned release.
What You'll Build
A production-ready GitHub repository built with an engineering mindset from commit zero, where every file, directory, and convention answers one question: "Why am I doing this?"
By the end of this project, you'll have:
- A Git installation configured with your identity, SSH authentication, and conventional commit conventions.
- A cloud-operations-homelab repository with layered directories, a formal versioning system (Phase 1.0 through 9.0), engineering documentation standards, and a portfolio-grade README.
- A working GitHub Actions CI pipeline and your first tagged release (v1.0.0).
- Secret Mission: Your first Architecture Decision Record documenting the homelab hardware choice.
Are there any prerequisites?
You need a GitHub account before starting this project. If you do not have one yet, create a free account at github.com before moving to Step 1.
Install Git for Windows and Configure Your Identity
Every commit in your repository carries your name and email address. Before you write any code or documentation, you need Git installed and your identity configured.
In this step, you will install Git for Windows using the winget package manager, set your name and email, and confirm everything is working in PowerShell.
In this step, get ready to:
- Install Git for Windows via winget.
- Configure your Git identity (name, email, and default branch).
- Verify your configuration.
Install Git for Windows
Git for Windows bundles the git command-line tool, an SSH client, and other utilities you will use throughout this project. You will install it using winget, the built-in Windows package manager.
- Press the Windows key to open your search bar.
- Type Terminal and press Enter to open Windows Terminal.
- Check if Git is already installed by running this command:
git --version
✔️ I see version 2.55.0 or higher
Git is already installed and up to date. You are ready to configure your identity. Skip ahead to the next substep.
ⓧ I see an older version
You have an older version of Git installed. Upgrade to the latest version by running this command:
winget upgrade --id Git.Git -e --source winget
- After the upgrade finishes, close Windows Terminal completely.
- Reopen Windows Terminal (press the Windows key, type Terminal, press Enter).
- Confirm the upgrade by running:
git --version
You should see git version 2.55.0 or higher in the output.
ⓧ Command not found
Git is not installed yet. Install it by running this command:
winget install --id Git.Git -e --source winget
What does this command do?
- winget install tells the Windows package manager to download and install a package.
- --id Git.Git specifies the exact package identifier for Git for Windows.
- -e enforces an exact, case-sensitive match so you get the right package.
- --source winget limits the search to the winget community repository.
The installer may prompt you to agree to its license terms. Accept them to continue.
- After the installation finishes, close Windows Terminal completely.
- Reopen Windows Terminal (press the Windows key, type Terminal, press Enter).
- Confirm the installation by running:
git --version
You should see git version 2.55.0 or higher in the output.
Still seeing 'command not found' after installing?
Make sure you closed and reopened Windows Terminal after the install completed. New installations update your system PATH, but existing terminal sessions do not pick up the change automatically.
If it still does not work after reopening, try restarting your PC and then opening a fresh terminal.
Help me troubleshoot Git not being recognized in PowerShell after installing via winget.
Configure your Git identity
Git attaches your name and email to every commit you make. These values identify you as the author in your repository's history.
- Set your Git username, email, and default branch name by running these three commands:
git config --global user.name "[[YOUR_GIT_NAME="your full name"]]"
git config --global user.email "[[YOUR_GIT_EMAIL="your GitHub email address"]]"
git config --global init.defaultBranch main
What do these commands do?
- git config --global user.name sets the name that appears on every commit you make, across all repositories on your machine.
- git config --global user.email sets the email address attached to your commits. Use the same email tied to your GitHub account so GitHub links your commits to your profile.
- git config --global init.defaultBranch main tells Git to name the first branch main whenever you create a new repository. This is the modern convention.
Use your GitHub email
If you are not sure which email is tied to your GitHub account, go to github.com and check Settings > Emails. Using a matching email means GitHub can attribute your commits to your profile.
Verify your configuration
You now have Git installed and your identity configured. Confirm that all three values are saved correctly.
- List all your Git configuration settings by running:
git config --list
What should I see?
The output is a list of key-value pairs. Look for these three lines (your actual values will differ):
- user.name=Your Name confirms your name is set.
- user.email=you@example.com confirms your email is set.
- init.defaultbranch=main confirms new repos will use main as the default branch.
Missing one of the values?
If a value is missing from the output, re-run the corresponding git config --global command from the previous substep. Make sure you include the double quotes around your name and email.
Help me fix my Git config. I ran git config --list but some values are missing.
Your Git identity is locked in and ready to go. Next up, you will generate an SSH key and connect it to GitHub so you can push code without entering a password every time.
Generate an SSH Key and Connect to GitHub
SSH lets your computer prove its identity to GitHub without typing a password every time you push or pull code. It uses a key pair: one private key stays on your machine, one public key goes to GitHub.
In this step, you will generate an Ed25519 key pair, configure Windows to remember it, and register the public key with your GitHub account. This same SSH skill transfers directly to connecting to your homelab server later.
In this step, get ready to:
- Generate an Ed25519 SSH key pair.
- Add your public key to your GitHub account.
- Test the SSH connection to confirm authentication works.
Generate your SSH key pair and start the agent
An SSH key pair consists of a private key (your secret identity) and a public key (what you share with services like GitHub). The ssh-keygen command creates both files at once.
- Generate your SSH key pair by running this command in your PowerShell terminal:
ssh-keygen -t ed25519 -C "[[YOUR_EMAIL="your_email@example.com"]]"
What does this command do?
- -t ed25519 tells ssh-keygen to use the Ed25519 algorithm. It produces smaller, faster, more secure keys than RSA.
- -C adds a comment (your email) to the key so you can identify it later.
What prompts will I see?
The command asks two questions. Press Enter for both to accept the default file location and skip the passphrase:
- "Enter file in which to save the key" accepts the default path at ~/.ssh/id_ed25519.
- "Enter passphrase" can be left empty for this project. Just press Enter twice.
You should see output showing your key fingerprint and a randomart image. This confirms two files were created: id_ed25519 (private) and id_ed25519.pub (public).
Seeing a 'file already exists' warning?
If you previously generated an SSH key, the command warns before overwriting. Type y and press Enter to overwrite with a fresh key.
Help me troubleshoot my SSH key generation
Now you need to start the Windows SSH agent service so it can hold your private key in memory. This requires an elevated (Administrator) PowerShell window.
- Press the Windows key to open your search bar.
- Type PowerShell, then click Run as administrator on the right side.
- If a User Account Control prompt appears, click Yes to allow it.
- Start the SSH agent service by running these commands in the elevated PowerShell window:
# Configure the ssh-agent service to start manually
Get-Service -Name ssh-agent | Set-Service -StartupType Manual
# Start the service now
Start-Service ssh-agent
What does this do?
The ssh-agent is a Windows service that securely holds your private key in memory. By default it is disabled, so you need to enable and start it.
These commands require administrator privileges because they modify a Windows service. You only need to do this once.
- Verify the service is running by running:
Get-Service ssh-agent
You should see a status of Running in the output.
Service status shows Stopped?
Make sure you are running PowerShell as Administrator. The service commands fail silently without elevation. Close the current window and reopen it using Run as administrator.
Help me start the ssh-agent service on Windows
- Close the elevated PowerShell window. You are done with administrator privileges.
- Switch back to your regular PowerShell terminal from earlier.
- Add your private key to the agent by running this command:
ssh-add c:/Users/[[WINUSER="your Windows username"]]/.ssh/id_ed25519
What path do I use?
Replace the username placeholder with your actual Windows username. This is the same folder name you see when you open C:\Users\ in File Explorer.
For example, if your Windows username is alex, the command would be ssh-add c:/Users/alex/.ssh/id_ed25519.
You should see a message confirming the identity was added.
Seeing 'Error connecting to agent'?
This means the ssh-agent service is not running. Go back and complete the elevated PowerShell steps above to start the service.
You also need to tell Git to use the Windows system SSH (not the one bundled with Git for Windows). Run this command:
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
Help me fix my ssh-agent connection on Windows
Copy your public key and add it to GitHub
Your public key is the half you share with GitHub. It proves your identity without ever exposing your private key.
- Copy your public key to the clipboard by running this command:
cat ~/.ssh/id_ed25519.pub | clip
Why cat and pipe instead of clip directly?
In Windows Terminal with PowerShell, the < operator is reserved. Using cat piped to clip avoids a ParseError.
- Open your browser and go to github.com.
- Click your profile picture in the top-right corner.
- Click Settings.
- In the left sidebar, click SSH and GPG keys.
- Click New SSH key.
- In the Title field, enter a name like Desktop PC so you can identify this key later.
- Leave the Key type set to Authentication.
- Click into the Key field and paste with Ctrl+V.
- Click Add SSH key.
- If prompted, confirm your GitHub password.
You should see your new key listed on the SSH keys page with the title you chose.
Key not pasting correctly?
Make sure you copied the key using the cat | clip command above. If you opened the file manually, ensure you copied the entire line starting with ssh-ed25519 with no extra newlines or spaces.
Help me add my SSH key to GitHub
Test the SSH connection
Time to confirm everything is wired up correctly.
- Test your SSH connection to GitHub by running this command:
ssh -T git@github.com
What does this command do?
The -T flag disables terminal allocation (you do not need an interactive shell on GitHub). GitHub receives your public key, checks it against the one you just added, and responds with a greeting if the match succeeds.
- If prompted "Are you sure you want to continue connecting?", type yes and press Enter. This happens the first time you connect to a new SSH host.
You should see a message like: "Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access."
Seeing 'Permission denied (publickey)'?
This means GitHub could not match your key. Check these common causes:
- Make sure you added the .pub file (public key) to GitHub, not the private key.
- Confirm the ssh-agent is running and has your key loaded. Run ssh-add -l to check.
- If Git for Windows is using its own SSH instead of the Windows system SSH, run:
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
Help me fix SSH permission denied on GitHub
Your machine can now authenticate to GitHub without a password. Next up, you will create your repository and build the professional directory structure that underpins the entire homelab project.
Create the Repository and Establish the Directory Structure
With Git configured and SSH authenticated, you need a home for all your homelab work. A well-structured repository is your foundation for everything that follows.
In this step, you will create the cloud-operations-homelab repository on GitHub, clone it to your machine, and build out a professional directory structure with engineering documentation.
In this step, get ready to:
- Create the repository on GitHub and clone it locally over SSH.
- Build a layered directory structure for docs, IaC, containers, and monitoring.
- Add engineering documentation files that codify your standards from day one.
Create the repository on GitHub and clone it locally
You need an empty repository on GitHub so you can push your local work up to it. Creating it without any initialization files means you control exactly what goes in from the first commit.
- Open your browser and go to github.com.
- Click the + icon in the upper-right corner of the page.
- Select New repository.
- Enter cloud-operations-homelab in the Repository name field.
- Select Public for visibility.
- Leave all checkboxes under Initialize this repository with unchecked. Do not add a README, .gitignore, or license here.
- Click Create repository.
Why leave initialization unchecked?
You will create your own README, .gitignore, and LICENSE locally with carefully crafted content. Initializing through GitHub would create generic versions you would immediately overwrite.
- Return to your PowerShell terminal.
- Move to your Desktop by running this command:
cd ~/Desktop
- Clone your new repository over SSH by running this command:
git clone git@github.com:[[GITHUB_USERNAME="your-github-username"]]/cloud-operations-homelab.git
What does this command do?
The git clone command downloads your empty repository from GitHub to your local machine using the SSH connection you set up in the previous step. The git@github.com: prefix tells Git to use SSH instead of HTTPS.
- Move into your new repository folder by running:
cd cloud-operations-homelab
You should see a warning that you cloned an empty repository. This is expected.
Seeing "Permission denied (publickey)"?
This means your SSH key is not being found by the ssh-agent. Make sure the OpenSSH Authentication Agent service is running and your key is added. Run ssh-add ~/.ssh/id_ed25519 and try the clone command again.
Help me fix this SSH authentication error
Build the directory structure
A layered directory structure keeps your work organized as the project grows across 9 phases. Each directory has a specific purpose that maps to real DevOps workflows.
- Create all project directories by running this command:
mkdir docs/adr, docs/runbooks, docs/journal, scripts, ansible, terraform, docker, monitoring, .github/workflows
What are these directories for?
- docs/adr stores Architecture Decision Records explaining WHY you made each technical choice.
- docs/runbooks holds operational procedures you can follow step-by-step.
- docs/journal is your learning log and content pipeline for Medium/LinkedIn posts.
- scripts, ansible, terraform, docker, monitoring map to the tools you will use in later phases.
- .github/workflows is where GitHub Actions CI pipeline files live.
- Confirm the directories were created by running:
Get-ChildItem -Recurse -Directory
You should see all nine directories listed in the output.
Not seeing all directories?
Make sure you are inside the cloud-operations-homelab folder. Run pwd to check your current location. If you are not inside the repo, run cd ~/Desktop/cloud-operations-homelab first.
Help me fix my missing directories
Next, you need a .gitignore file to keep sensitive and generated files out of version control.
- Create the .gitignore file by running this command to open it in Notepad:
notepad .gitignore
- Notepad will ask if you want to create a new file. Click Yes.
- Paste the following content into the file:
# Terraform
*.tfstate
*.tfstate.backup
.terraform/
.terraform.lock.hcl
crash.log
# Ansible
*.retry
# Environment files
.env
.env.*
!.env.example
# Python
__pycache__/
*.py[cod]
venv/
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
# Secrets
*.pem
*.key
id_rsa
id_ed25519
What does this .gitignore do?
Each section blocks a category of files from being tracked by Git. Terraform state files contain sensitive infrastructure details. Ansible retry files are temporary. Environment files (.env) often contain secrets.
The Secrets section prevents accidentally committing SSH keys or certificates to your public repository.
- Save the file in Notepad with Ctrl+S and close it.
✔️ Awesome, I've got everything!
Great. Make sure you have saved .gitignore before moving on.
ⓧ I'd like to double check the full code
# Terraform
*.tfstate
*.tfstate.backup
.terraform/
.terraform.lock.hcl
crash.log
# Ansible
*.retry
# Environment files
.env
.env.*
!.env.example
# Python
__pycache__/
*.py[cod]
venv/
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
# Secrets
*.pem
*.key
id_rsa
id_ed25519
Add the engineering documentation files
These files define how your project operates. Each one codifies a standard that makes every future commit, journal entry, and decision record consistent and explainable.
- Create the LICENSE file by running:
notepad LICENSE
- Click Yes to create the new file.
- Paste the following content, replacing the name placeholder with your full name:
MIT License
Copyright (c) 2026 [[YOURNAME="your full name"]]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Why MIT License?
The MIT License is one of the most permissive open-source licenses. It allows anyone to use, modify, and distribute your code with minimal restrictions. For a portfolio project, it signals that you understand licensing and want your work to be accessible.
- Save with Ctrl+S and close Notepad.
- Create the STANDARDS.md file by running:
notepad STANDARDS.md
- Click Yes to create the new file.
- Paste the following content:
# Engineering Standards
This document defines the documentation and engineering conventions for this repository. Every contributor (including future-me) follows these standards.
## Documentation Philosophy
Every action in this repository answers one question: **Why am I doing this?**
Do not write:
> Installed UFW.
Write:
> Configured UFW to enforce a default-deny policy while allowing SSH traffic on port 22. This reduces the attack surface by blocking all unsolicited inbound connections while maintaining remote administration capability.
This approach demonstrates understanding, not just execution. It produces documentation you can walk a hiring manager through with confidence.
## Commit Message Convention
This repository uses Conventional Commits (conventionalcommits.org):
```text
<type>: <description>
[optional body explaining WHY, not just what]
```
Types:
- `feat` - New capability or infrastructure addition
- `fix` - Bug fix or correction
- `docs` - Documentation only (ADRs, runbooks, journal entries)
- `ci` - CI/CD pipeline changes
- `refactor` - Restructuring without changing behavior
- `security` - Security hardening or vulnerability fix
- `chore` - Maintenance tasks (dependency updates, cleanup)
Examples:
- `feat: deploy prometheus node-exporter for system metrics collection`
- `security: configure UFW default-deny policy with SSH exception`
- `docs: add ADR-003 monitoring stack selection`
## Architecture Decision Records (ADRs)
Every significant technical decision gets an ADR in `docs/adr/`. Use the MADR format:
1. Title (ADR-NNN: Short descriptive name)
2. Status (Proposed, Accepted, Deprecated, Superseded)
3. Context (What problem are we solving? What constraints exist?)
4. Decision (What did we choose and why?)
5. Consequences (Positive, negative, and mitigations)
Write ADRs as if explaining to an interviewer. They are your interview preparation.
## Versioning System
This project uses phase-based versioning with git tags:
| Tag | Phase | Description |
|-----|-------|-------------|
| v1.0.0 | Phase 1.0 | Ubuntu Server Foundation |
| v2.0.0 | Phase 2.0 | Secure Remote Administration |
| v3.0.0 | Phase 3.0 | Bash Automation |
| v4.0.0 | Phase 4.0 | Docker Platform |
| v5.0.0 | Phase 5.0 | Monitoring Stack |
| v6.0.0 | Phase 6.0 | Infrastructure as Code |
| v7.0.0 | Phase 7.0 | CI/CD Pipeline |
| v8.0.0 | Phase 8.0 | Configuration Management |
| v9.0.0 | Phase 9.0 | Kubernetes Expansion |
Minor versions (e.g., v4.1.0, v4.2.0) mark significant milestones within a phase.
Patch versions (e.g., v4.1.1) mark fixes or documentation updates.
Each phase completion includes:
- A git tag on the main branch
- An updated ROADMAP.md with completed items checked
- A CHANGELOG.md entry summarizing what was accomplished
- A LinkedIn/Medium post documenting the phase (drafted in docs/journal/)
## Journal Entries
Journal entries in `docs/journal/` serve a dual purpose:
1. Learning log: capture what you built, what you struggled with, and what you learned
2. Content pipeline: each entry is a draft for a Medium/LinkedIn post
Format: `NNN-short-title.md` (e.g., `001-project-kickoff.md`)
Write as if explaining to a peer who is six months behind you on the same journey.
## Runbook Format
Runbooks in `docs/runbooks/` follow this structure:
1. Purpose (what this runbook accomplishes and when to use it)
2. Prerequisites (what must be true before starting)
3. Steps (numbered, with the WHY for each command)
4. Validation (how to confirm success)
5. Rollback (how to undo if something goes wrong)
What does STANDARDS.md define?
This file codifies five conventions: a documentation philosophy (explain WHY, not just what), Conventional Commits message format, the MADR template for Architecture Decision Records, your phase-based semantic versioning system, and formatting rules for journal entries and runbooks.
Think of it as a contribution guide for a team of one. It keeps future-you consistent and gives hiring managers evidence of engineering discipline.
- Save with Ctrl+S and close Notepad.
- Create the CHANGELOG.md file by running:
notepad CHANGELOG.md
- Click Yes to create the new file.
- Paste the following content:
# Changelog
All notable changes to this project are documented here. This project uses phase-based semantic versioning (see STANDARDS.md).
## [v1.0.0] - 2026-07-04
Phase 1.0: Ubuntu Server Foundation (Repository Initialization)
### Added
- Repository structure with layered directories (docs, scripts, ansible, terraform, docker, monitoring)
- Engineering standards documentation (STANDARDS.md)
- Phase 1.0-9.0 versioning system with git tags
- Project roadmap (ROADMAP.md) with 9-phase breakdown
- GitHub Actions CI pipeline for YAML and Markdown linting
- MIT License
- .gitignore configured for DevOps toolchain
- First journal entry documenting project kickoff
What is a changelog?
A changelog tracks what changed in each release. It follows the "Keep a Changelog" convention used by professional open-source projects. Each version entry lists what was added, changed, or removed so anyone (including hiring managers) can trace the project's evolution.
- Save with Ctrl+S and close Notepad.
- Create the ROADMAP.md file by running:
notepad ROADMAP.md
- Click Yes to create the new file.
- Paste the following content:
# Cloud Operations Homelab - Project Roadmap
Target Role: Cloud DevOps Engineer
Timeline: 6-7 months (July 2026 - January 2027)
Hardware: Lenovo ThinkPad T530 (i7-3520M, 16GB RAM, 238GB SSD)
## Versioning
Each phase maps to a major version tag. Progress is tracked here and in git history.
| Phase | Version | Focus | Status |
|-------|---------|-------|--------|
| 1.0 | v1.0.0 | Ubuntu Server Foundation | In Progress |
| 2.0 | v2.0.0 | Secure Remote Administration | Planned |
| 3.0 | v3.0.0 | Bash Automation | Planned |
| 4.0 | v4.0.0 | Docker Platform | Planned |
| 5.0 | v5.0.0 | Monitoring Stack | Planned |
| 6.0 | v6.0.0 | Infrastructure as Code | Planned |
| 7.0 | v7.0.0 | CI/CD Pipeline | Planned |
| 8.0 | v8.0.0 | Configuration Management | Planned |
| 9.0 | v9.0.0 | Kubernetes Expansion | Planned |
## Phase 1.0: Ubuntu Server Foundation
Goal: Establish the physical server and repository infrastructure.
- [x] Initialize repository with professional structure and engineering standards
- [x] CI pipeline (linting) active
- [ ] Install Ubuntu Server 24.04 LTS on Lenovo T530
- [ ] Configure headless WiFi connectivity
- [ ] Establish SSH access from desktop workstation
## Phase 2.0: Secure Remote Administration
Goal: Harden the server for safe remote-only operation.
- [ ] SSH key-only authentication (disable password auth)
- [ ] UFW firewall with default-deny inbound policy
- [ ] fail2ban for brute-force protection
- [ ] Automatic security updates (unattended-upgrades)
- [ ] System logging and log rotation
## Phase 3.0: Bash Automation
Goal: Automate repetitive tasks and establish scripting patterns.
- [ ] System health check script
- [ ] Automated backup script
- [ ] Server bootstrap/setup script
- [ ] Scheduled maintenance via cron
## Phase 4.0: Docker Platform
Goal: Containerize services and establish orchestration patterns.
- [ ] Install and configure Docker Engine
- [ ] Deploy services via docker-compose
- [ ] Reverse proxy (Traefik or Nginx Proxy Manager)
- [ ] Container health checks and restart policies
- [ ] Docker logging and cleanup automation
## Phase 5.0: Monitoring Stack
Goal: Full observability into system and container health.
- [ ] Prometheus for metrics collection
- [ ] Node Exporter for system metrics
- [ ] Grafana dashboards for visualization
- [ ] Alerting (ntfy or similar push notifications)
- [ ] Log aggregation
## Phase 6.0: Infrastructure as Code
Goal: Define all infrastructure declaratively and reproducibly.
- [ ] Terraform for cloud-adjacent resources
- [ ] Codify infrastructure decisions as reusable modules
- [ ] State management and backend configuration
## Phase 7.0: CI/CD Pipeline
Goal: Automate testing, validation, and deployment.
- [ ] GitHub Actions for automated testing on push
- [ ] Deployment pipeline (git push triggers server changes)
- [ ] Infrastructure validation in CI
- [ ] GitOps workflow for configuration changes
## Phase 8.0: Configuration Management
Goal: Manage server state declaratively with Ansible.
- [ ] Ansible playbooks for server configuration
- [ ] Role-based organization
- [ ] Automate Docker deployments with Ansible
- [ ] Idempotent server setup (rebuild from scratch)
## Phase 9.0: Kubernetes Expansion
Goal: Container orchestration at a production-like level.
- [ ] k3s single-node Kubernetes cluster
- [ ] Helm charts for service deployment
- [ ] Ingress controller
- [ ] Disaster recovery and backup automation
- [ ] Final portfolio polish and interview preparation
What does the roadmap communicate?
The roadmap maps your 6-7 month journey into 9 phases, each tagged with a semantic version. Hiring managers can see your planned progression from OS fundamentals through Kubernetes. The checkboxes make progress visible at a glance.
Each phase builds on the previous one. This mirrors how production environments grow in real organizations.
- Save with Ctrl+S and close Notepad.
- Back in PowerShell, verify all files are visible to Git by running:
git status
You should see all your new files listed as untracked files in red text. This confirms Git sees them but has not staged them yet.
Not seeing all your files?
If git status shows fewer files than expected, check that you saved each file. Notepad sometimes saves with a .txt extension by default. When saving in Notepad, make sure Save as type is set to All Files (*.*) instead of Text Documents (*.txt).
Help me fix my missing or incorrectly named files
✔️ Awesome, I've got everything!
Great. You should see .gitignore, LICENSE, STANDARDS.md, CHANGELOG.md, and ROADMAP.md all listed as untracked in the git status output.
ⓧ I'd like to double check the full code
Here is the complete .gitignore for comparison:
# Terraform
*.tfstate
*.tfstate.backup
.terraform/
.terraform.lock.hcl
crash.log
# Ansible
*.retry
# Environment files
.env
.env.*
!.env.example
# Python
__pycache__/
*.py[cod]
venv/
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
# Secrets
*.pem
*.key
id_rsa
id_ed25519
Here is the complete LICENSE for comparison (remember to use your own name):
MIT License
Copyright (c) 2026 [[YOURNAME="your full name"]]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Here is the complete STANDARDS.md for comparison:
# Engineering Standards
This document defines the documentation and engineering conventions for this repository. Every contributor (including future-me) follows these standards.
## Documentation Philosophy
Every action in this repository answers one question: **Why am I doing this?**
Do not write:
> Installed UFW.
Write:
> Configured UFW to enforce a default-deny policy while allowing SSH traffic on port 22. This reduces the attack surface by blocking all unsolicited inbound connections while maintaining remote administration capability.
This approach demonstrates understanding, not just execution. It produces documentation you can walk a hiring manager through with confidence.
## Commit Message Convention
This repository uses Conventional Commits (conventionalcommits.org):
```text
<type>: <description>
[optional body explaining WHY, not just what]
```
Types:
- `feat` - New capability or infrastructure addition
- `fix` - Bug fix or correction
- `docs` - Documentation only (ADRs, runbooks, journal entries)
- `ci` - CI/CD pipeline changes
- `refactor` - Restructuring without changing behavior
- `security` - Security hardening or vulnerability fix
- `chore` - Maintenance tasks (dependency updates, cleanup)
Examples:
- `feat: deploy prometheus node-exporter for system metrics collection`
- `security: configure UFW default-deny policy with SSH exception`
- `docs: add ADR-003 monitoring stack selection`
## Architecture Decision Records (ADRs)
Every significant technical decision gets an ADR in `docs/adr/`. Use the MADR format:
1. Title (ADR-NNN: Short descriptive name)
2. Status (Proposed, Accepted, Deprecated, Superseded)
3. Context (What problem are we solving? What constraints exist?)
4. Decision (What did we choose and why?)
5. Consequences (Positive, negative, and mitigations)
Write ADRs as if explaining to an interviewer. They are your interview preparation.
## Versioning System
This project uses phase-based versioning with git tags:
| Tag | Phase | Description |
|-----|-------|-------------|
| v1.0.0 | Phase 1.0 | Ubuntu Server Foundation |
| v2.0.0 | Phase 2.0 | Secure Remote Administration |
| v3.0.0 | Phase 3.0 | Bash Automation |
| v4.0.0 | Phase 4.0 | Docker Platform |
| v5.0.0 | Phase 5.0 | Monitoring Stack |
| v6.0.0 | Phase 6.0 | Infrastructure as Code |
| v7.0.0 | Phase 7.0 | CI/CD Pipeline |
| v8.0.0 | Phase 8.0 | Configuration Management |
| v9.0.0 | Phase 9.0 | Kubernetes Expansion |
Minor versions (e.g., v4.1.0, v4.2.0) mark significant milestones within a phase.
Patch versions (e.g., v4.1.1) mark fixes or documentation updates.
Each phase completion includes:
- A git tag on the main branch
- An updated ROADMAP.md with completed items checked
- A CHANGELOG.md entry summarizing what was accomplished
- A LinkedIn/Medium post documenting the phase (drafted in docs/journal/)
## Journal Entries
Journal entries in `docs/journal/` serve a dual purpose:
1. Learning log: capture what you built, what you struggled with, and what you learned
2. Content pipeline: each entry is a draft for a Medium/LinkedIn post
Format: `NNN-short-title.md` (e.g., `001-project-kickoff.md`)
Write as if explaining to a peer who is six months behind you on the same journey.
## Runbook Format
Runbooks in `docs/runbooks/` follow this structure:
1. Purpose (what this runbook accomplishes and when to use it)
2. Prerequisites (what must be true before starting)
3. Steps (numbered, with the WHY for each command)
4. Validation (how to confirm success)
5. Rollback (how to undo if something goes wrong)
Here is the complete CHANGELOG.md for comparison:
# Changelog
All notable changes to this project are documented here. This project uses phase-based semantic versioning (see STANDARDS.md).
## [v1.0.0] - 2026-07-04
Phase 1.0: Ubuntu Server Foundation (Repository Initialization)
### Added
- Repository structure with layered directories (docs, scripts, ansible, terraform, docker, monitoring)
- Engineering standards documentation (STANDARDS.md)
- Phase 1.0-9.0 versioning system with git tags
- Project roadmap (ROADMAP.md) with 9-phase breakdown
- GitHub Actions CI pipeline for YAML and Markdown linting
- MIT License
- .gitignore configured for DevOps toolchain
- First journal entry documenting project kickoff
Here is the complete ROADMAP.md for comparison:
# Cloud Operations Homelab - Project Roadmap
Target Role: Cloud DevOps Engineer
Timeline: 6-7 months (July 2026 - January 2027)
Hardware: Lenovo ThinkPad T530 (i7-3520M, 16GB RAM, 238GB SSD)
## Versioning
Each phase maps to a major version tag. Progress is tracked here and in git history.
| Phase | Version | Focus | Status |
|-------|---------|-------|--------|
| 1.0 | v1.0.0 | Ubuntu Server Foundation | In Progress |
| 2.0 | v2.0.0 | Secure Remote Administration | Planned |
| 3.0 | v3.0.0 | Bash Automation | Planned |
| 4.0 | v4.0.0 | Docker Platform | Planned |
| 5.0 | v5.0.0 | Monitoring Stack | Planned |
| 6.0 | v6.0.0 | Infrastructure as Code | Planned |
| 7.0 | v7.0.0 | CI/CD Pipeline | Planned |
| 8.0 | v8.0.0 | Configuration Management | Planned |
| 9.0 | v9.0.0 | Kubernetes Expansion | Planned |
## Phase 1.0: Ubuntu Server Foundation
Goal: Establish the physical server and repository infrastructure.
- [x] Initialize repository with professional structure and engineering standards
- [x] CI pipeline (linting) active
- [ ] Install Ubuntu Server 24.04 LTS on Lenovo T530
- [ ] Configure headless WiFi connectivity
- [ ] Establish SSH access from desktop workstation
## Phase 2.0: Secure Remote Administration
Goal: Harden the server for safe remote-only operation.
- [ ] SSH key-only authentication (disable password auth)
- [ ] UFW firewall with default-deny inbound policy
- [ ] fail2ban for brute-force protection
- [ ] Automatic security updates (unattended-upgrades)
- [ ] System logging and log rotation
## Phase 3.0: Bash Automation
Goal: Automate repetitive tasks and establish scripting patterns.
- [ ] System health check script
- [ ] Automated backup script
- [ ] Server bootstrap/setup script
- [ ] Scheduled maintenance via cron
## Phase 4.0: Docker Platform
Goal: Containerize services and establish orchestration patterns.
- [ ] Install and configure Docker Engine
- [ ] Deploy services via docker-compose
- [ ] Reverse proxy (Traefik or Nginx Proxy Manager)
- [ ] Container health checks and restart policies
- [ ] Docker logging and cleanup automation
## Phase 5.0: Monitoring Stack
Goal: Full observability into system and container health.
- [ ] Prometheus for metrics collection
- [ ] Node Exporter for system metrics
- [ ] Grafana dashboards for visualization
- [ ] Alerting (ntfy or similar push notifications)
- [ ] Log aggregation
## Phase 6.0: Infrastructure as Code
Goal: Define all infrastructure declaratively and reproducibly.
- [ ] Terraform for cloud-adjacent resources
- [ ] Codify infrastructure decisions as reusable modules
- [ ] State management and backend configuration
## Phase 7.0: CI/CD Pipeline
Goal: Automate testing, validation, and deployment.
- [ ] GitHub Actions for automated testing on push
- [ ] Deployment pipeline (git push triggers server changes)
- [ ] Infrastructure validation in CI
- [ ] GitOps workflow for configuration changes
## Phase 8.0: Configuration Management
Goal: Manage server state declaratively with Ansible.
- [ ] Ansible playbooks for server configuration
- [ ] Role-based organization
- [ ] Automate Docker deployments with Ansible
- [ ] Idempotent server setup (rebuild from scratch)
## Phase 9.0: Kubernetes Expansion
Goal: Container orchestration at a production-like level.
- [ ] k3s single-node Kubernetes cluster
- [ ] Helm charts for service deployment
- [ ] Ingress controller
- [ ] Disaster recovery and backup automation
- [ ] Final portfolio polish and interview preparation
Your repository skeleton is in place. Next up, you will write your portfolio README, your first journal entry, and make your first commit to bring this repository to life on GitHub.
Write Your Portfolio README, Journal Entry, and Push
Your repository has structure, standards, and a roadmap. But a repository without a README is invisible to anyone who visits it on GitHub.
In this step, you will write a README that tells hiring managers exactly what they are looking at and why it matters. You will also capture your first journal entry and publish everything to GitHub with your first tagged release.
In this step, get ready to:
- Write a portfolio-grade README aimed at hiring managers.
- Write your first journal entry as a learning log and LinkedIn draft.
- Commit, push, and tag v1.0.0 to mark Phase 1.0 initialization.
Write the README.md
The README is the first thing anyone sees when they visit your repository. It communicates your intent, your roadmap, and your engineering standards in one page.
- Create a new file called README.md in the root of your cloud-operations-homelab folder and paste the following content:
# Cloud Operations Homelab
Self-hosted infrastructure on a repurposed Lenovo T530. Real hardware, real networking, documented decisions, engineering mindset from day one.
## Objective
Target Role: Cloud DevOps Engineer
Timeline: 6-7 months (July 2026 - January 2027)
Approach: Build production-like infrastructure on physical hardware. Document every decision. Demonstrate progressive skill building with an engineering mindset.
## Hardware
| Component | Spec |
|-----------|------|
| Machine | Lenovo ThinkPad T530 |
| CPU | Intel i7-3520M @ 2.90GHz (2 cores, 4 threads) |
| RAM | 16GB |
| Storage | 238GB SSD (Gigaston Prime Series) |
| Network | WiFi (headless, SSH-only access) |
| OS | Ubuntu Server (planned) |
## Project Versioning
| Phase | Version | Focus |
|-------|---------|-------|
| 1.0 | v1.0.0 | Ubuntu Server Foundation |
| 2.0 | v2.0.0 | Secure Remote Administration |
| 3.0 | v3.0.0 | Bash Automation |
| 4.0 | v4.0.0 | Docker Platform |
| 5.0 | v5.0.0 | Monitoring Stack |
| 6.0 | v6.0.0 | Infrastructure as Code |
| 7.0 | v7.0.0 | CI/CD Pipeline |
| 8.0 | v8.0.0 | Configuration Management |
| 9.0 | v9.0.0 | Kubernetes Expansion |
See [ROADMAP.md](ROADMAP.md) for detailed phase breakdowns and progress tracking.
See [CHANGELOG.md](CHANGELOG.md) for release history.
## Tech Stack (Planned)
| Layer | Tools |
|-------|-------|
| OS | Ubuntu Server |
| Containers | Docker, docker-compose |
| IaC | Terraform, Ansible |
| Monitoring | Prometheus, Grafana |
| CI/CD | GitHub Actions |
| Networking | UFW, SSH, reverse proxy |
| Orchestration | k3s (Kubernetes) |
## Repository Layout
```text
.
├── docs/
│ ├── adr/ # Architecture Decision Records
│ ├── runbooks/ # Operational procedures
│ └── journal/ # Learning journal and Medium/LinkedIn drafts
├── scripts/ # Shell scripts and automation
├── ansible/ # Ansible playbooks and roles
├── terraform/ # Terraform configurations
├── docker/ # Docker compose stacks
├── monitoring/ # Prometheus, Grafana configs
├── .github/
│ └── workflows/ # CI/CD pipelines
├── STANDARDS.md # Engineering documentation conventions
├── ROADMAP.md # Phase-based project roadmap
├── CHANGELOG.md # Release history
├── README.md
├── LICENSE
└── .gitignore
```
## Documentation Philosophy
Every action in this repository answers: **Why am I doing this?**
This is not a collection of commands copied from tutorials. Every configuration choice is documented with its reasoning, trade-offs, and alternatives considered. See [STANDARDS.md](STANDARDS.md) for the full engineering conventions.
Architecture Decision Records in `docs/adr/` capture the thinking behind every significant choice. Read them to understand how I approach engineering problems.
## Current Status
Phase 1.0: Ubuntu Server Foundation - In Progress
Current Version: v1.0.0
- [x] Repository initialized with professional structure
- [x] Engineering standards established (STANDARDS.md)
- [x] CI pipeline (linting) active
- [x] Phase versioning system implemented
- [ ] Ubuntu Server installed on T530
- [ ] SSH access configured
## For Recruiters
This repository documents a hands-on infrastructure project built on real hardware. It demonstrates:
- Engineering mindset from commit one (every action explains WHY)
- Structured decision-making via Architecture Decision Records
- Phase-based project management with semantic versioning
- Progressive complexity (OS, security, containers, IaC, monitoring, CI/CD, orchestration)
- Technical writing and documentation as a first-class skill
- Real-world problem solving (networking, security, automation on constrained hardware)
Start with:
1. [STANDARDS.md](STANDARDS.md) to see how I think about engineering documentation
2. [docs/adr/](docs/adr/) to see how I make and communicate technical decisions
3. [CHANGELOG.md](CHANGELOG.md) and git tags to trace the progression from v1.0.0 through each phase
What does this README do?
This README is structured to answer the questions a hiring manager asks when they land on your repo. The Objective section states your target role and timeline upfront. The Hardware table shows you are working on real infrastructure.
The For Recruiters section at the bottom gives a hiring manager a guided reading path. Instead of wandering your repo aimlessly, they know exactly where to start and what each section demonstrates.
Why a dedicated section for recruiters?
Most developers never explain how to read their portfolio. A recruiter spending 30 seconds on your profile needs explicit direction. The numbered reading path (STANDARDS first, ADRs second, CHANGELOG third) tells them a story in three clicks.
- Save README.md.
README not rendering correctly on GitHub later?
Markdown tables require exact spacing. Make sure each row has the same number of pipe characters (|) and that the header separator row uses dashes (---).
help me fix my markdown table formatting
Write your first journal entry
Journal entries in docs/journal/ serve two purposes. They are your personal learning log and the draft for your first LinkedIn or Medium post.
- Create a new file called 001-project-kickoff.md inside the docs/journal/ folder and paste the following content:
# 001: Project Kickoff - Building a Homelab to Land a Cloud DevOps Role
Date: 2026-07-04
Phase: 1.0
Version: v1.0.0
## What I Built Today
Initialized the `cloud-operations-homelab` repository with a professional structure, engineering documentation standards, CI pipeline, and a 9-phase roadmap.
## The Story
I have a Lenovo ThinkPad T530 sitting on my desk. It is the same laptop I used to study for my Salesforce Administrator certification while working full-time as a security officer. Every night after my shift, I would open this laptop and study. It got me into tech.
Now I am repurposing it as a headless Ubuntu server. Over the next 6-7 months, I will build production-like infrastructure on it: containers, monitoring, infrastructure as code, CI/CD pipelines, and Kubernetes. All documented. All version-controlled. All explainable to a hiring manager.
## Why a Physical Homelab
Cloud free tiers abstract away the operating system, networking, and hardware layers. I want to demonstrate that I understand what happens beneath the managed services. When I tell an interviewer I configured a firewall, I mean I wrote the UFW rules on a real machine. When I say I troubleshot a networking issue, I mean my WiFi dropped at 2am and I had to figure out why my SSH session died.
## What This Proves
By the end of this project, I will be able to walk a hiring manager through 9 phases of progressive infrastructure work on real hardware. Every decision is documented. Every configuration explains WHY. The git history tells a story of continuous learning and engineering discipline.
## LinkedIn/Medium Angle
"I repurposed the same laptop that got me into tech. The same $50 ThinkPad I used to study for my first certification is now running Ubuntu Server, Docker containers, Prometheus monitoring, and a Kubernetes cluster. Here is how I am building my way into Cloud DevOps engineering."
## Next Steps
- Acquire a USB flash drive for Ubuntu Server installation
- Install Ubuntu Server 24.04 LTS on the T530
- Configure headless WiFi and SSH access
What makes this a good journal entry?
It tells a story, not a task list. The Story section gives personal context that makes your project memorable in an interview. The LinkedIn/Medium Angle section gives you a ready-to-publish hook when you complete Phase 1.0.
Every future journal entry follows this same pattern: what you built, why it matters, and how to communicate it publicly.
- Save docs/journal/001-project-kickoff.md.
- Confirm both files exist by running:
Get-ChildItem README.md, docs/journal/001-project-kickoff.md
You should see both files listed with their sizes.
File not found?
Make sure your terminal is in the cloud-operations-homelab directory. Run pwd to check your current location. The journal file must be inside docs/journal/, not in the repo root.
help me find where I saved my journal file
Stage, commit, push, and tag your first release
Everything is written locally. Now you will publish all of it to GitHub in one commit and mark this moment with a version tag.
- Stage all files and create your first commit using Conventional Commits format by running these commands:
git add .
git commit -m "feat: initialize cloud-operations-homelab repository"
What do these commands do?
git add . stages every untracked and modified file in the repository. The dot means "everything in the current directory and below."
git commit -m creates a snapshot of the staged files. The feat: prefix follows the Conventional Commits standard you defined in STANDARDS.md. It signals that this commit adds a new capability.
- Push your commit to GitHub and create the v1.0.0 tag by running these commands:
git push origin main
git tag -a v1.0.0 -m "Phase 1.0: Repository initialization"
git push origin v1.0.0
What does tagging do?
A git tag marks a specific commit as a named release point. The -a flag creates an annotated tag (which stores the tagger, date, and message). This is how professional open-source projects mark releases.
Hiring managers can click through your tags on GitHub to see the repository at each phase. The progression from v1.0.0 to v9.0.0 tells a story of continuous growth.
- Open your browser and visit your repository at github.com/YOUR_USERNAME/cloud-operations-homelab.
- You should see the full directory structure and your rendered README with tables, the repository layout, and the For Recruiters section.
- Click Tags (in the sidebar or under Releases) to confirm v1.0.0 appears.
Push rejected or authentication failed?
If you see a permission denied error, your SSH key may not be loaded in the agent. Run ssh -T git@github.com to test your connection. If it fails, restart the ssh-agent and re-add your key.
If the push is rejected because the remote has changes you do not have locally, run git pull --rebase origin main first, then push again.
help me fix my git push to GitHub
Your repository is live and tagged. Next up, you will add automated linting with GitHub Actions so that every push is validated.
Add a GitHub Actions CI Workflow
Your repository is live on GitHub with a professional structure, documentation standards, and a tagged release. One piece is missing: automated quality checks that run every time you push code.
In this step, you will create a GitHub Actions workflow that automatically lints your YAML and Markdown files on every push. This catches formatting errors before they accumulate across nine phases of work.
In this step, get ready to:
- Create a GitHub Actions workflow file that triggers on pushes to main.
- Add YAML and Markdown linting steps to catch formatting issues automatically.
- Commit, push, and verify the workflow runs successfully on GitHub.
Create the workflow file
GitHub Actions workflows live in .github/workflows/ as YAML files. Each file defines when to run and what steps to execute.
- In your PowerShell terminal, make sure you are inside the cloud-operations-homelab folder.
- Create the workflow file by running this command:
New-Item -Path .github/workflows/lint.yml -ItemType File
- Open .github/workflows/lint.yml in your text editor and paste the following content:
name: Lint
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
What does this code do?
- name: Lint gives the workflow a readable name that appears in the GitHub Actions tab.
- The on: block tells GitHub to run this workflow whenever you push to main or open a pull request targeting main.
- runs-on: ubuntu-latest spins up a fresh Linux virtual machine for the job.
- actions/checkout@v7 clones your repository into that VM so the linting tools can access your files.
Add the linting steps
The checkout step gives the workflow access to your files. Now you need steps that actually inspect them for quality issues.
- In lint.yml, add the following steps directly below the uses: actions/checkout@v7 line:
- name: Install linters
run: |
pip install yamllint
npm install -g markdownlint-cli2
- name: Lint YAML files
run: yamllint . --strict || true
- name: Lint Markdown files
run: markdownlint-cli2 "**/*.md" || true
What do these steps do?
- The first step installs two linting tools: yamllint for YAML validation and markdownlint-cli2 for Markdown formatting checks.
- yamllint . --strict scans all YAML files in the repository for syntax and formatting issues.
- markdownlint-cli2 "**/*.md" checks every Markdown file for consistent formatting.
- The || true at the end of each lint command prevents the workflow from failing on warnings. Your initial files may trigger minor style warnings that are fine to address later.
- Save lint.yml.
File not saving correctly?
- YAML is indentation-sensitive. Make sure you use spaces (not tabs) and the indentation matches exactly. Each - name: step should be indented with 6 spaces (aligned under - uses:).
- Confirm the file is saved at the exact path .github/workflows/lint.yml. A misplaced file will not be detected by GitHub Actions.
Why is my lint.yml file not being recognized by GitHub Actions?
✔️ Awesome, I've got everything!
Great. Double check you have saved the file before moving on.
ⓧ I'd like to double check the full code
Here is the complete .github/workflows/lint.yml file:
name: Lint
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Install linters
run: |
pip install yamllint
npm install -g markdownlint-cli2
- name: Lint YAML files
run: yamllint . --strict || true
- name: Lint Markdown files
run: markdownlint-cli2 "**/*.md" || true
Commit, push, and verify the workflow
Your workflow file is ready locally. Pushing it to GitHub triggers the workflow automatically.
- Stage and commit the workflow file using conventional commit format by running these commands:
git add .github/workflows/lint.yml
git commit -m "ci: add yaml and markdown linting workflow"
Why the ci: prefix?
Your STANDARDS.md defines ci as the conventional commit type for CI/CD pipeline changes. Following your own standards from day one builds the habit.
- Push the commit to GitHub by running:
git push origin main
- Open your browser and navigate to your repository on GitHub.
- Click the **Actions** tab at the top of the repository page.
- You should see a workflow run named ci: add yaml and markdown linting workflow with a green checkmark indicating it passed.
What if the run is still in progress?
GitHub Actions workflows take 30-60 seconds to complete. If you see a yellow spinning icon, wait a moment and refresh the page. It should turn green.
Seeing a red X instead of a green checkmark?
- Click on the failed run to see the logs. Look for YAML indentation errors in the workflow file itself.
- Make sure the run: | line in the Install linters step has a pipe character (|) after it. This tells YAML to treat the next lines as a multi-line string.
- Compare your file against the full code in the double-check tab above. Fix any differences, commit, and push again.
My GitHub Actions workflow is failing with a red X. Help me debug.
Secret mission
Write Your First Architecture Decision Record
Your docs/adr/ directory is sitting empty. Senior engineers use Architecture Decision Records to document the WHY behind every significant technical choice. It is time to write your first one, following the MADR format you defined in STANDARDS.md, and establish the pattern you will follow for every major decision in this homelab.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely on your local machine and a free GitHub account. There are no ongoing costs or running services to worry about.
Decide whether to keep your resources as they are, pause background services, or delete everything entirely.
Resources you used:
- Git for Windows (installed via winget).
- SSH key pair (local files and added to your GitHub account).
- GitHub repository cloud-operations-homelab.
- Local repository clone on your Desktop.
Keep everything running
No action needed. Choose this if you are continuing to Phase 2.0 (Ubuntu Server installation) or plan to keep building on this repository.
- Your Git installation, SSH key, and local repository are all ready for the next phase.
- The ssh-agent service will continue running in the background so your key stays loaded.
- Your GitHub repository is live and publicly visible at your URL.
Pause - I'll come back to this later
Stop the SSH agent service to free up background resources. Your files and repository stay intact for when you return.
- Stop the SSH agent service by running this in PowerShell:
Stop-Service ssh-agent
- Your local repository, SSH key files, and GitHub repository all remain untouched.
- When you return, start the agent again with Start-Service ssh-agent and re-add your key with ssh-add.
Delete - I don't want to use this again
Remove all project resources from your machine and GitHub account. This is permanent.
- Delete the local repository clone by running this in PowerShell:
Remove-Item -Recurse -Force ~\Desktop\cloud-operations-homelab
- Remove your SSH key from GitHub. Go to your GitHub account **Settings**, then **SSH and GPG keys**. Click the delete button next to the key you added in this project.
- Delete the local SSH key files by running:
Remove-Item ~\.ssh\id_ed25519, ~\.ssh\id_ed25519.pub
- Delete the GitHub repository. Go to your repository page, click **Settings** in the top navigation bar, scroll down to the **Danger Zone** section, and click **Delete this repository**. Confirm by typing your repository name when prompted.
- Uninstall Git for Windows by running:
winget uninstall --id Git.Git
- Stop the SSH agent service by running:
Stop-Service ssh-agent
Nice Work!
Nice Work!
You just built a production-ready GitHub repository from scratch with an engineering mindset baked into every file. Your cloud-operations-homelab repository is live, versioned, and ready to grow with you over the next 6-7 months.
You learned how to:
- Build a professionally structured GitHub repository with layered directories, engineering documentation standards (STANDARDS.md), and a formal Phase 1.0-9.0 versioning system tracked through git tags.
- Set up automated CI with GitHub Actions for YAML and Markdown linting, and tag your first formal release (v1.0.0).
- Write a portfolio-grade README with a "For Recruiters" section and a journal entry designed to double as your first LinkedIn/Medium post.
- Secret Mission: Document your first Architecture Decision Record using the MADR format, establishing a pattern of professional decision-making from day one.
Ready to quiz yourself?