Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ba68de68d | |||
| d1d38df0e4 | |||
| 62e5027d24 | |||
| 3d596b984b |
@@ -0,0 +1,2 @@
|
|||||||
|
ansible_user: adyrem
|
||||||
|
ansible_ssh_common_args: "-o ProxyJump=root@192.168.1.10 -o StrictHostKeyChecking=no"
|
||||||
@@ -22,6 +22,11 @@ all:
|
|||||||
hosts:
|
hosts:
|
||||||
gitea:
|
gitea:
|
||||||
|
|
||||||
|
claude_code_vms:
|
||||||
|
hosts:
|
||||||
|
claude-code:
|
||||||
|
ansible_host: 10.10.2.10
|
||||||
|
|
||||||
pihole_servers:
|
pihole_servers:
|
||||||
hosts:
|
hosts:
|
||||||
pihole:
|
pihole:
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
- name: Configure Claude Code VM
|
||||||
|
hosts: claude_code_vms
|
||||||
|
roles:
|
||||||
|
- common
|
||||||
|
- node_exporter
|
||||||
|
- promtail
|
||||||
|
- claude_code
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
files/homelab_ed25519
|
||||||
|
files/claude-code_ed25519
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
- name: Install Claude Code dependencies
|
||||||
|
community.general.pacman:
|
||||||
|
name:
|
||||||
|
- nodejs
|
||||||
|
- npm
|
||||||
|
- ansible
|
||||||
|
- python-pip
|
||||||
|
- tmux
|
||||||
|
- git
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
- name: Install Claude Code CLI
|
||||||
|
community.general.npm:
|
||||||
|
name: "@anthropic-ai/claude-code"
|
||||||
|
global: true
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Deploy homelab SSH private key
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: homelab_ed25519
|
||||||
|
dest: /home/{{ admin_user }}/.ssh/homelab_ed25519
|
||||||
|
owner: "{{ admin_user }}"
|
||||||
|
group: "{{ admin_user }}"
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Deploy claude-code SFTP private key
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: claude-code_ed25519
|
||||||
|
dest: /home/{{ admin_user }}/.ssh/claude-code_ed25519
|
||||||
|
owner: "{{ admin_user }}"
|
||||||
|
group: "{{ admin_user }}"
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Write SSH client config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: ssh_config.j2
|
||||||
|
dest: /home/{{ admin_user }}/.ssh/config
|
||||||
|
owner: "{{ admin_user }}"
|
||||||
|
group: "{{ admin_user }}"
|
||||||
|
mode: "0600"
|
||||||
|
|
||||||
|
- name: Write tmux config
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /home/{{ admin_user }}/.tmux.conf
|
||||||
|
owner: "{{ admin_user }}"
|
||||||
|
group: "{{ admin_user }}"
|
||||||
|
mode: "0644"
|
||||||
|
content: |
|
||||||
|
set -g default-terminal "screen-256color"
|
||||||
|
set -g history-limit 50000
|
||||||
|
set -g mouse on
|
||||||
|
set -g base-index 1
|
||||||
|
set -g escape-time 10
|
||||||
|
bind r source-file ~/.tmux.conf \; display "Reloaded"
|
||||||
|
|
||||||
|
- name: Clone homelab repo
|
||||||
|
ansible.builtin.git:
|
||||||
|
repo: "http://10.10.1.125:3000/adyrem/homelab.git"
|
||||||
|
dest: /home/{{ admin_user }}/dev/homelab
|
||||||
|
version: main
|
||||||
|
become_user: "{{ admin_user }}"
|
||||||
|
become: true
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Proxmox host — jump host only, no shell
|
||||||
|
Host proxmox
|
||||||
|
HostName 192.168.1.10
|
||||||
|
User root
|
||||||
|
IdentityFile ~/.ssh/homelab_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
|
||||||
|
# Proxmox SFTP — write files to host workspace
|
||||||
|
Host proxmox-sftp
|
||||||
|
HostName 192.168.1.10
|
||||||
|
User claude-code
|
||||||
|
IdentityFile ~/.ssh/claude-code_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
|
||||||
|
# Infra VMs — via ProxyJump through Proxmox
|
||||||
|
Host gitea-vm
|
||||||
|
HostName 10.10.1.125
|
||||||
|
User adyrem
|
||||||
|
ProxyJump proxmox
|
||||||
|
IdentityFile ~/.ssh/homelab_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
|
||||||
|
Host monitoring-vm
|
||||||
|
HostName 10.10.1.137
|
||||||
|
User adyrem
|
||||||
|
ProxyJump proxmox
|
||||||
|
IdentityFile ~/.ssh/homelab_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
|
||||||
|
Host pihole-ct
|
||||||
|
HostName 10.10.1.2
|
||||||
|
User root
|
||||||
|
ProxyJump proxmox
|
||||||
|
IdentityFile ~/.ssh/homelab_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
|
||||||
|
Host traefik-ct
|
||||||
|
HostName 10.10.1.3
|
||||||
|
User root
|
||||||
|
ProxyJump proxmox
|
||||||
|
IdentityFile ~/.ssh/homelab_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
{
|
||||||
|
"annotations": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:75",
|
||||||
|
"builtIn": 1,
|
||||||
|
"datasource": "-- Grafana --",
|
||||||
|
"enable": true,
|
||||||
|
"hide": true,
|
||||||
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
|
"name": "Annotations & Alerts",
|
||||||
|
"type": "dashboard"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"description": "Log Viewer Dashboard for Loki",
|
||||||
|
"editable": false,
|
||||||
|
"gnetId": 13639,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"id": 1684514089902080,
|
||||||
|
"iteration": 1608932746420,
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:59",
|
||||||
|
"icon": "bolt",
|
||||||
|
"includeVars": true,
|
||||||
|
"keepTime": true,
|
||||||
|
"tags": [],
|
||||||
|
"targetBlank": true,
|
||||||
|
"title": "View In Explore",
|
||||||
|
"type": "link",
|
||||||
|
"url": "/explore?orgId=1&left=[\"now-1h\",\"now\",\"Loki\",{\"expr\":\"{job=\\\"$app\\\"}\"},{\"ui\":[true,true,true,\"none\"]}]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:61",
|
||||||
|
"icon": "external link",
|
||||||
|
"tags": [],
|
||||||
|
"targetBlank": true,
|
||||||
|
"title": "Learn LogQL",
|
||||||
|
"type": "link",
|
||||||
|
"url": "https://grafana.com/docs/loki/latest/logql/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": true,
|
||||||
|
"dashLength": 10,
|
||||||
|
"dashes": false,
|
||||||
|
"datasource": "P8E80F9AEF21F6940",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {},
|
||||||
|
"links": []
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"fill": 1,
|
||||||
|
"fillGradient": 0,
|
||||||
|
"gridPos": {
|
||||||
|
"h": 3,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 0
|
||||||
|
},
|
||||||
|
"hiddenSeries": false,
|
||||||
|
"id": 6,
|
||||||
|
"legend": {
|
||||||
|
"avg": false,
|
||||||
|
"current": false,
|
||||||
|
"max": false,
|
||||||
|
"min": false,
|
||||||
|
"show": false,
|
||||||
|
"total": false,
|
||||||
|
"values": false
|
||||||
|
},
|
||||||
|
"lines": false,
|
||||||
|
"linewidth": 1,
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"percentage": false,
|
||||||
|
"pluginVersion": "7.1.0",
|
||||||
|
"pointradius": 2,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"spaceLength": 10,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "sum(count_over_time({job=\"$app\"} |= \"$search\" [$__interval]))",
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeRegions": [],
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"buckets": null,
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:168",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$$hashKey": "object:169",
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"yaxis": {
|
||||||
|
"align": false,
|
||||||
|
"alignLevel": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": "P8E80F9AEF21F6940",
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"custom": {}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 25,
|
||||||
|
"w": 24,
|
||||||
|
"x": 0,
|
||||||
|
"y": 3
|
||||||
|
},
|
||||||
|
"id": 2,
|
||||||
|
"maxDataPoints": "",
|
||||||
|
"options": {
|
||||||
|
"showLabels": false,
|
||||||
|
"showTime": true,
|
||||||
|
"sortOrder": "Descending",
|
||||||
|
"wrapLogMessage": false
|
||||||
|
},
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"expr": "{job=\"$app\"} |= \"$search\" | logfmt",
|
||||||
|
"hide": false,
|
||||||
|
"legendFormat": "",
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "",
|
||||||
|
"transparent": true,
|
||||||
|
"type": "logs"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"refresh": false,
|
||||||
|
"schemaVersion": 26,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": [],
|
||||||
|
"templating": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"allValue": null,
|
||||||
|
"current": {},
|
||||||
|
"datasource": "P8E80F9AEF21F6940",
|
||||||
|
"definition": "label_values(job)",
|
||||||
|
"hide": 0,
|
||||||
|
"includeAll": false,
|
||||||
|
"label": "App",
|
||||||
|
"multi": false,
|
||||||
|
"name": "app",
|
||||||
|
"options": [],
|
||||||
|
"query": "label_values(job)",
|
||||||
|
"refresh": 1,
|
||||||
|
"regex": "",
|
||||||
|
"skipUrlSync": false,
|
||||||
|
"sort": 0,
|
||||||
|
"tagValuesQuery": "",
|
||||||
|
"tags": [],
|
||||||
|
"tagsQuery": "",
|
||||||
|
"type": "query",
|
||||||
|
"useTags": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"current": {
|
||||||
|
"selected": false,
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
"hide": 0,
|
||||||
|
"label": "String Match",
|
||||||
|
"name": "search",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"selected": true,
|
||||||
|
"text": "",
|
||||||
|
"value": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"query": "",
|
||||||
|
"skipUrlSync": false,
|
||||||
|
"type": "textbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-1h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {
|
||||||
|
"hidden": false,
|
||||||
|
"refresh_intervals": [
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timezone": "",
|
||||||
|
"title": "Logs / App",
|
||||||
|
"uid": "sadlil-loki-apps-dashboard",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
[OPTIONS]
|
||||||
|
enable: 1
|
||||||
|
|
||||||
|
[ALIASES]
|
||||||
|
lan 192.168.1.0/24
|
||||||
|
infra_net 10.10.1.0/24
|
||||||
|
dev_net 10.10.2.0/24
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[OPTIONS]
|
||||||
|
enable: 1
|
||||||
|
log_level_in: nolog
|
||||||
|
log_level_out: nolog
|
||||||
|
|
||||||
|
[RULES]
|
||||||
|
IN ACCEPT -source 192.168.1.0/24 -p tcp -dport 22
|
||||||
|
IN ACCEPT -source 192.168.1.0/24 -p tcp -dport 8006
|
||||||
|
IN ACCEPT -source 192.168.1.0/24 -p tcp -dport 3128
|
||||||
|
IN ACCEPT -source 10.10.0.0/16 -p udp -dport 53
|
||||||
|
IN ACCEPT -source 10.10.0.0/16 -p tcp -dport 53
|
||||||
|
IN ACCEPT -p icmp
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
arch: amd64
|
||||||
|
cores: 1
|
||||||
|
features: nesting=1
|
||||||
|
hostname: pihole
|
||||||
|
memory: 512
|
||||||
|
nameserver: 8.8.8.8
|
||||||
|
net0: name=eth0,bridge=vmbr1,firewall=0,gw=10.10.1.1,hwaddr=BC:24:11:D6:DD:FF,ip=10.10.1.2/24,type=veth
|
||||||
|
onboot: 1
|
||||||
|
ostype: debian
|
||||||
|
rootfs: local-zfs:subvol-103-disk-0,size=4G
|
||||||
|
swap: 0
|
||||||
|
unprivileged: 1
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
arch: amd64
|
||||||
|
cores: 1
|
||||||
|
hostname: traefik
|
||||||
|
memory: 256
|
||||||
|
nameserver: 10.10.1.2
|
||||||
|
net0: name=eth0,bridge=vmbr1,firewall=1,gw=10.10.1.1,hwaddr=BC:24:11:8E:D3:36,ip=10.10.1.3/24,type=veth
|
||||||
|
onboot: 1
|
||||||
|
ostype: debian
|
||||||
|
rootfs: local-zfs:subvol-104-disk-0,size=2G
|
||||||
|
swap: 0
|
||||||
|
unprivileged: 1
|
||||||
|
|
||||||
|
[pve:pending]
|
||||||
|
nameserver: 8.8.8.8
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
auto lo
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
iface nic0 inet manual
|
||||||
|
|
||||||
|
auto vmbr0
|
||||||
|
iface vmbr0 inet static
|
||||||
|
address 192.168.1.10/24
|
||||||
|
gateway 192.168.1.1
|
||||||
|
bridge-ports nic0
|
||||||
|
bridge-stp off
|
||||||
|
bridge-fd 0
|
||||||
|
post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 80 -j DNAT --to-destination 10.10.1.3:80
|
||||||
|
post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 443 -j DNAT --to-destination 10.10.1.3:443
|
||||||
|
post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 80 -j DNAT --to-destination 10.10.1.3:80
|
||||||
|
post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 443 -j DNAT --to-destination 10.10.1.3:443
|
||||||
|
post-up iptables -t nat -A PREROUTING -i vmbr0 -p udp --dport 53 -j DNAT --to-destination 10.10.1.2:53
|
||||||
|
post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 53 -j DNAT --to-destination 10.10.1.2:53
|
||||||
|
post-up iptables -t nat -A POSTROUTING -p udp -d 10.10.1.2 --dport 53 -j MASQUERADE
|
||||||
|
post-up iptables -t nat -A POSTROUTING -p tcp -d 10.10.1.2 --dport 53 -j MASQUERADE
|
||||||
|
post-down iptables -t nat -D PREROUTING -i vmbr0 -p udp --dport 53 -j DNAT --to-destination 10.10.1.2:53
|
||||||
|
post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 53 -j DNAT --to-destination 10.10.1.2:53
|
||||||
|
post-down iptables -t nat -D POSTROUTING -p udp -d 10.10.1.2 --dport 53 -j MASQUERADE
|
||||||
|
post-down iptables -t nat -D POSTROUTING -p tcp -d 10.10.1.2 --dport 53 -j MASQUERADE
|
||||||
|
|
||||||
|
|
||||||
|
source /etc/network/interfaces.d/*
|
||||||
|
|
||||||
|
auto vmbr1
|
||||||
|
iface vmbr1 inet static
|
||||||
|
address 10.10.1.1/24
|
||||||
|
bridge-ports none
|
||||||
|
bridge-stp off
|
||||||
|
bridge-fd 0
|
||||||
|
post-up iptables -t nat -A POSTROUTING -s 10.10.1.0/24 -o vmbr0 -j MASQUERADE
|
||||||
|
post-down iptables -t nat -D POSTROUTING -s 10.10.1.0/24 -o vmbr0 -j MASQUERADE
|
||||||
|
|
||||||
|
auto vmbr2
|
||||||
|
iface vmbr2 inet static
|
||||||
|
address 10.10.2.1/24
|
||||||
|
bridge-ports none
|
||||||
|
bridge-stp off
|
||||||
|
bridge-fd 0
|
||||||
|
post-up iptables -t nat -A POSTROUTING -s 10.10.2.0/24 -o vmbr0 -j MASQUERADE
|
||||||
|
post-down iptables -t nat -D POSTROUTING -s 10.10.2.0/24 -o vmbr0 -j MASQUERADE
|
||||||
|
|
||||||
|
auto vmbr3
|
||||||
|
iface vmbr3 inet static
|
||||||
|
address 10.10.3.1/24
|
||||||
|
bridge-ports none
|
||||||
|
bridge-stp off
|
||||||
|
bridge-fd 0
|
||||||
|
post-up iptables -t nat -A POSTROUTING -s 10.10.3.0/24 -o vmbr0 -j MASQUERADE
|
||||||
|
post-down iptables -t nat -D POSTROUTING -s 10.10.3.0/24 -o vmbr0 -j MASQUERADE
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
agent: enabled=1
|
||||||
|
bios: ovmf
|
||||||
|
boot: order=scsi0
|
||||||
|
cicustom: user=local:snippets/claude-code-userdata.yaml
|
||||||
|
citype: nocloud
|
||||||
|
cores: 4
|
||||||
|
cpu: host
|
||||||
|
efidisk0: local-zfs:vm-105-disk-0,efitype=4m,pre-enrolled-keys=0,size=1M
|
||||||
|
ide2: local-zfs:vm-105-cloudinit,media=cdrom
|
||||||
|
ipconfig0: ip=10.10.2.10/24,gw=10.10.2.1
|
||||||
|
machine: q35
|
||||||
|
memory: 8192
|
||||||
|
name: claude-code
|
||||||
|
nameserver: 10.10.1.2
|
||||||
|
net0: virtio=BC:24:11:E3:A1:D1,bridge=vmbr2,firewall=1
|
||||||
|
onboot: 1
|
||||||
|
ostype: l26
|
||||||
|
scsi0: local-zfs:vm-105-disk-1,iothread=1,size=20G
|
||||||
|
scsihw: virtio-scsi-single
|
||||||
|
searchdomain: homelab
|
||||||
|
smbios1: uuid=cc68aa1f-affe-42ee-8086-ba94b69573af
|
||||||
|
vga: qxl
|
||||||
|
vmgenid: 511710d7-9a40-43ef-901e-0a2de8344f5b
|
||||||
Reference in New Issue
Block a user