Add Proxmox host role, WireGuard VPN, and public Gitea via Traefik HTTPS
Ansible Lint / lint (push) Successful in 4s
Ansible Lint / lint (push) Successful in 4s
Proxmox host role: - Admin user setup, SSH hardening (port 2222, no root login) - claude-code SFTP chroot user - Unattended upgrades, DuckDNS dynamic DNS updater (vault-encrypted token) - WireGuard VPN server (10.10.10.0/24) with Fedora client registered - Proxmox firewall management via pvesh API (idempotent Python script) Public Gitea exposure: - Traefik: add HTTPS entrypoint, Let's Encrypt ACME (HTTP-01), StripPrefix middleware for /git subpath, HTTP→HTTPS redirect - Gitea ROOT_URL updated to https://adyrem.duckdns.org/git/ - Pi-hole split DNS: adyrem.duckdns.org → 10.10.1.3 for internal hairpin bypass SSH config fixes: - StrictHostKeyChecking no → accept-new across all hosts - Proxmox jump host: port 2222, user adyrem (root login disabled) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
# host.yml — Proxmox Host Playbook
|
||||
|
||||
Configures the Proxmox host (`192.168.1.10`) with:
|
||||
|
||||
- Admin user (`adyrem`) with SSH key auth and passwordless sudo
|
||||
- `claude-code` SFTP-only user, chrooted to `/home/claude-code/workspace`
|
||||
- SSH hardened: key-only auth, root login disabled, port changed to 2222
|
||||
- Unattended security upgrades (Debian security channel only)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Proxmox is freshly installed and accessible as `root` via SSH on port 22
|
||||
- Ansible is installed on the machine running the playbook
|
||||
- Vault password is at `~/.config/homelab/vault_pass`
|
||||
- Repo is cloned and you're in the `ansible/` directory
|
||||
|
||||
---
|
||||
|
||||
## First run (bootstrap)
|
||||
|
||||
The first run connects as `root` because `adyrem` doesn't exist yet.
|
||||
`group_vars/proxmox_hosts/vars.yml` is already set for this — no changes needed.
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/host.yml
|
||||
```
|
||||
|
||||
What happens:
|
||||
1. Creates `adyrem` with your SSH key and passwordless sudo
|
||||
2. Creates `claude-code` user with SFTP-only access
|
||||
3. Changes SSH port to 2222 and disables root login
|
||||
4. Restarts sshd — **root SSH access ends here**
|
||||
|
||||
---
|
||||
|
||||
## After the first run
|
||||
|
||||
Update `inventory/group_vars/proxmox_hosts/vars.yml` to connect as `adyrem`:
|
||||
|
||||
```yaml
|
||||
ansible_user: adyrem
|
||||
ansible_become: true
|
||||
ansible_become_method: sudo
|
||||
ansible_port: 2222
|
||||
```
|
||||
|
||||
Verify you can still connect before relying on this:
|
||||
|
||||
```bash
|
||||
ssh -p 2222 adyrem@192.168.1.10
|
||||
```
|
||||
|
||||
All subsequent runs use:
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/host.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## claude-code SFTP access
|
||||
|
||||
The `claude-code` user can only SFTP into `/home/claude-code/workspace`. No shell, no TCP forwarding, no escape from the chroot.
|
||||
|
||||
From the Claude Code VM:
|
||||
|
||||
```bash
|
||||
sftp -P 2222 claude-code@192.168.1.10
|
||||
# lands in /workspace (which is /home/claude-code/workspace on the host)
|
||||
```
|
||||
|
||||
The private key for this user lives in the Claude Code VM at `~/.ssh/claude-code_ed25519`.
|
||||
The corresponding public key is committed at `keys/claude-code_ed25519.pub`.
|
||||
|
||||
---
|
||||
|
||||
## Re-running safely
|
||||
|
||||
The playbook is idempotent. Re-running it after the group_vars update will:
|
||||
- Ensure all config is still correct
|
||||
- Apply any template changes (sshd drop-in, unattended-upgrades)
|
||||
- Restart sshd only if the config changed
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
# Proxmox host configuration: admin user, claude-code SFTP user, SSH hardening,
|
||||
# unattended security upgrades.
|
||||
#
|
||||
# BOOTSTRAP NOTE: First run connects as root (see group_vars/proxmox_hosts/vars.yml).
|
||||
# After the first run, root SSH login is disabled — update the group_vars to:
|
||||
# ansible_user: adyrem
|
||||
# ansible_become: true
|
||||
# ansible_port: 2222
|
||||
- name: Configure Proxmox host
|
||||
hosts: proxmox_hosts
|
||||
roles:
|
||||
- proxmox_host
|
||||
@@ -0,0 +1,111 @@
|
||||
# Adding a new WireGuard client
|
||||
|
||||
## Current peer assignments
|
||||
|
||||
| Name | IP |
|
||||
|--------|--------------|
|
||||
| server | 10.10.10.1 |
|
||||
| fedora | 10.10.10.2 |
|
||||
|
||||
Pick the next free IP (10.10.10.3, 10.10.10.4, …) for each new machine.
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Generate a keypair on the new machine
|
||||
|
||||
**Linux / macOS:**
|
||||
```bash
|
||||
wg genkey | tee ~/wg-client.key | wg pubkey
|
||||
```
|
||||
|
||||
**Windows** (WireGuard app installed):
|
||||
Open the WireGuard app → Add Tunnel → Add empty tunnel. It generates a keypair and shows the public key at the top.
|
||||
|
||||
Copy the **public key** — you need it in Step 2.
|
||||
Keep the **private key** local. Never commit it to git.
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Register the peer in Ansible
|
||||
|
||||
Edit `ansible/inventory/group_vars/proxmox_hosts/vars.yml` and add an entry to `wireguard_peers`:
|
||||
|
||||
```yaml
|
||||
wireguard_peers:
|
||||
- name: fedora
|
||||
public_key: "ivtchk9pxEwYwusMzmn7Uq89LFV3uB1I8iYto0EJuy4="
|
||||
allowed_ips: 10.10.10.2/32
|
||||
- name: my-new-machine # ← add this
|
||||
public_key: "<public key from Step 1>"
|
||||
allowed_ips: 10.10.10.X/32 # ← next free IP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Push the peer to the server
|
||||
|
||||
```bash
|
||||
cd ansible && ansible-playbook playbooks/host.yml
|
||||
```
|
||||
|
||||
The server will accept connections from the new client immediately after this.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Create the client config
|
||||
|
||||
Use the template below. Store it in a location that is **not** committed to git.
|
||||
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 10.10.10.X/32
|
||||
PrivateKey = <private key from Step 1>
|
||||
DNS = 10.10.1.2
|
||||
|
||||
[Peer]
|
||||
PublicKey = UJaAvoT65+qC7NdD4lKFK+/J1OxKBYp1ZY3ynHjqcHE=
|
||||
Endpoint = adyrem.duckdns.org:51820
|
||||
AllowedIPs = 10.10.10.0/24, 10.10.1.0/24, 10.10.2.0/24
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
|
||||
`AllowedIPs` is a split tunnel — only homelab traffic goes through the VPN.
|
||||
Replace `adyrem.duckdns.org` with `192.168.1.10` when connecting from inside the LAN.
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Connect
|
||||
|
||||
**Linux (one-off):**
|
||||
```bash
|
||||
sudo wg-quick up /path/to/wg0.conf
|
||||
# disconnect: sudo wg-quick down /path/to/wg0.conf
|
||||
```
|
||||
|
||||
**Linux (persistent, starts on boot):**
|
||||
```bash
|
||||
sudo cp wg0.conf /etc/wireguard/wg0.conf
|
||||
sudo systemctl enable --now wg-quick@wg0
|
||||
```
|
||||
|
||||
**Windows / macOS / Android / iOS:**
|
||||
Import the config file into the WireGuard app, then toggle the tunnel on.
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — Verify
|
||||
|
||||
```bash
|
||||
ping 10.10.10.1 # Proxmox host
|
||||
ping 10.10.1.137 # monitoring VM
|
||||
# Proxmox web UI: https://10.10.10.1:8006
|
||||
# Grafana: http://10.10.1.137:3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Removing a client
|
||||
|
||||
1. Delete the peer entry from `wireguard_peers` in `group_vars/proxmox_hosts/vars.yml`
|
||||
2. Run `ansible-playbook playbooks/host.yml`
|
||||
3. The client's public key is removed from the server — existing sessions drop immediately
|
||||
Reference in New Issue
Block a user