home lab init

This commit is contained in:
plasmagoat 2025-06-03 23:07:46 +02:00
commit 7278922625
65 changed files with 27336 additions and 0 deletions

3
ansible/README.me Normal file
View file

@ -0,0 +1,3 @@
ansible-playbook -i inventory.yml books/bootstrap/bootstrap-proxmox.yml
ansible-playbook -i inventory.yml books/upload-nix-image.yml

3
ansible/ansible.cfg Normal file
View file

@ -0,0 +1,3 @@
[defaults]
roles_path = ./roles
inventory = ./inventory.yml

View file

@ -0,0 +1,40 @@
- name: Bootstrap Proxmox Server
hosts: proxmox
become: true
pre_tasks:
- name: Remove enterprise repository
ansible.builtin.apt_repository:
update_cache: false
repo: deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise
state: absent
- name: Remove enterprise pbs repository
ansible.builtin.apt_repository:
update_cache: false
repo: deb https://enterprise.proxmox.com/debian/pbs bookworm InRelease
state: absent
- name: Remove enterprise ceph repository
ansible.builtin.apt_repository:
update_cache: false
repo: deb https://enterprise.proxmox.com/debian/ceph-quincy bookworm enterprise
state: absent
- name: Add community repository
ansible.builtin.apt_repository:
update_cache: true
repo: deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription
state: present
tasks:
- name: Ensure ethtool offload post-up is present for eno1
ansible.builtin.lineinfile:
path: /etc/network/interfaces
line: "\tpost-up ethtool -K eno2 tso off gso off"
insertafter: "^iface eno2 inet manual"
state: present
backup: yes
- import_tasks: ../tasks/packages.yml
# - import_tasks: ../tasks/locale.yml
# - import_tasks: ../tasks/keyboard.yml
# - import_tasks: ../tasks/users.yml
# - import_tasks: ../tasks/ssh.yml

View file

@ -0,0 +1,82 @@
- name: Clone VM from Template
hosts: proxmox
become: true
vars_prompt:
- name: "template_vmid"
prompt: "Enter VMID for the template"
private: no
default: "9000"
- name: "new_vmid"
prompt: "Enter the new VMID"
private: no
default: "9001"
- name: "new_name"
prompt: "Enter name for the new VM"
private: no
default: "nixos-clone"
vars:
storage: "local-lvm"
tasks:
- name: Clone the template
ansible.builtin.command: >
qm clone {{ template_vmid }} {{ new_vmid }} --name {{ new_name }}
- name: Resize disk to 10G
ansible.builtin.command: >
qm resize {{ new_vmid }} virtio0 +5G
- name: Set cloud-init params
ansible.builtin.command: >
qm set {{ new_vmid }}
--ciuser root
--cipassword root
--sshkey /root/.ssh/id_rsa.pub
--ipconfig0 ip=dhcp
- name: Start the new VM
ansible.builtin.command: >
qm start {{ new_vmid }}
- name: Wait for QEMU Guest Agent to come online
retries: 20
delay: 5
ansible.builtin.shell: |
qm guest exec {{ new_vmid }} -- true
register: qga_check
until: qga_check.rc == 0
- name: Get IP addresses via QEMU Guest Agent
ansible.builtin.shell: |
qm guest cmd {{ new_vmid }} network-get-interfaces
register: qga_json
failed_when: qga_json.rc != 0
- name: Parse out eth0s IPv4 address
ansible.builtin.set_fact:
vm_ipv4: >-
{{
(
qga_json.stdout
| from_json
| selectattr('name','equalto','eth0')
| map(attribute='ip-addresses')
| first
| selectattr('ip-address-type','equalto','ipv4')
| map(attribute='ip-address')
| first
)
}}
- name: Show the VMs IP
ansible.builtin.debug:
msg: "VM {{ new_vmid }} ({{ new_name }}) reports IPv4: {{ vm_ipv4 }}"
# - name: Add new VMs IP to in-memory inventory (for later tasks)
# ansible.builtin.add_host:
# name: "nixos-{{ new_vmid }}"
# ansible_host: "{{ vm_ipv4 }}"
# ansible_user: root

View file

@ -0,0 +1,81 @@
- name: Build and Upload NixOS Image, Restore and Convert to Template
hosts: nodes
gather_facts: false
vars:
flake_name: "{{ flake | default('base') }}"
image_dir: "{{ playbook_dir }}/../../nixos"
result_path: "{{ image_dir }}/result"
dest_dir: "/var/lib/vz/dump/"
tasks:
- name: Build NixOS base image
ansible.builtin.shell: nix build .#{{ flake_name }}
args:
chdir: "{{ image_dir }}"
register: build_result
delegate_to: localhost
- name: Get built image file
ansible.builtin.find:
paths: "{{ result_path }}"
patterns: "*.vma.zst"
register: built_image
delegate_to: localhost
- name: Fail if no image was built
ansible.builtin.fail:
msg: "No image file found in result/"
when: built_image.files | length == 0
delegate_to: localhost
- name: Set fact for built image path
ansible.builtin.set_fact:
local_image_path: "{{ built_image.files[0].path | realpath }}"
image_filename: "{{ built_image.files[0].path | basename }}"
delegate_to: localhost
- name: Copy image to Proxmox
ansible.builtin.copy:
src: "{{ local_image_path }}"
dest: "{{ dest_dir }}"
- name: Remove local build result
ansible.builtin.file:
path: "{{ result_path }}"
state: absent
delegate_to: localhost
- name: Restore and Convert to Template on Proxmox
hosts: nodes
become: true
vars_prompt:
- name: "vmid"
prompt: "Enter VMID for the template"
private: no
default: "9000"
- name: "vmname"
prompt: "Enter name for the Proxmox template"
private: no
default: "nixos-base"
vars:
image_path: "/var/lib/vz/dump/{{ image_filename }}"
cpu_cores: 2
memory_mb: 2048
tasks:
- name: Restore VM from image
ansible.builtin.command: >
qmrestore {{ image_path }} {{ vmid }} --unique true
args:
creates: "/etc/pve/qemu-server/{{ vmid }}.conf"
- name: Set name, CPU and memory
ansible.builtin.command: >
qm set {{ vmid }} --cores {{ cpu_cores }} --memory {{ memory_mb }} --name {{ vmname }}
- name: Convert VM to template
ansible.builtin.command: qm template {{ vmid }}

View file

@ -0,0 +1,13 @@
- name: Install Nix (multi-user mode)
ansible.builtin.shell: |
if [ ! -x /nix/var/nix/profiles/default/bin/nix ]; then
curl -L https://nixos.org/nix/install | bash -s -- --daemon
fi
args:
creates: /nix
- name: Enable flakes in nix config
ansible.builtin.copy:
dest: /etc/nix/nix.conf
content: |
experimental-features = nix-command flakes

View file

@ -0,0 +1,25 @@
- name: Stop nix-daemon service
ansible.builtin.systemd:
name: nix-daemon.service
state: stopped
enabled: no
ignore_errors: yes
- name: Remove /nix directory
ansible.builtin.file:
path: /nix
state: absent
- name: Remove nix entries from root's shell config
ansible.builtin.lineinfile:
path: /root/.bashrc
regexp: "^.*nix.*$"
state: absent
ignore_errors: yes
- name: Remove nix entries from root's shell profile
ansible.builtin.lineinfile:
path: /root/.profile
regexp: "^.*nix.*$"
state: absent
ignore_errors: yes

View file

@ -0,0 +1,17 @@
- name: Ensure NFS subfolders exist on NAS
hosts: nas
become: true
tasks:
- name: Ensure /volume1/data exists
file:
path: /volume1/data
state: directory
mode: "0755"
- name: Ensure /volume1/data/forgejo exists
file:
path: /volume1/data/forgejo
state: directory
owner: 992
group: 990
mode: "0770"

View file

@ -0,0 +1,2 @@
- name: Set keyboard layout
ansible.builtin.command: localectl set-keymap dk

View file

@ -0,0 +1,10 @@
- name: Ensure locale is set
ansible.builtin.locale_gen:
name: "en_DK.UTF-8"
state: present
- name: Set system locale
ansible.builtin.command: localectl set-locale LANG=en_DK.UTF-8
- name: Set timezone
ansible.builtin.command: timedatectl set-timezone Europe/Copenhagen

View file

@ -0,0 +1,8 @@
- name: Install required packages
ansible.builtin.apt:
name:
- python3
- curl
- git
state: present
update_cache: yes

View file

@ -0,0 +1,14 @@
- name: Ensure user plasmagoat exists
ansible.builtin.user:
name: plasmagoat
groups: wheel,docker,networkmanager
shell: /usr/bin/zsh
state: present
- name: Set authorized SSH keys for plasmagoat
ansible.posix.authorized_key:
user: plasmagoat
key: "{{ item }}"
loop:
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCeg/n/..."
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICUP7m8jZJ..."

View file

@ -0,0 +1,16 @@
- name: Disable PasswordAuthentication in sshd_config
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^PasswordAuthentication"
line: "PasswordAuthentication no"
- name: Disable KbdInteractiveAuthentication in sshd_config
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "^KbdInteractiveAuthentication"
line: "KbdInteractiveAuthentication no"
- name: Restart sshd to apply changes
ansible.builtin.service:
name: ssh
state: restarted

View file

@ -0,0 +1,8 @@
---
- name: Upgrade
hosts: nodes
tasks:
- name: Upgrade
tags: upgrade
ansible.builtin.apt:
upgrade: dist

View file

@ -0,0 +1,6 @@
- name: Deploy and bootstrap mailer VM
hosts: mailer
become: true
roles:
- common

View file

@ -0,0 +1,26 @@
- name: Build and Upload NixOS Image
hosts: nodes
vars:
current_date: "{{ ansible_date_time.date }}"
flake_name: "{{ flake | default('proxmox') }}"
tasks:
- name: create iso
ansible.builtin.shell: nix build .#{{ flake_name }}
args:
chdir: "{{ playbook_dir }}/../../nixos/nixos-base-image"
delegate_to: localhost
run_once: true
- name: copy the backup
ansible.builtin.copy:
src: "{{ item }}"
dest: "/var/lib/vz/dump/"
with_fileglob:
- "{{ playbook_dir }}/../../nixos/nixos-base-image/result/*.zst"
- name: remove build result
ansible.builtin.file:
path: "{{ playbook_dir }}/../../nixos/nixos-base-image/result"
state: absent
delegate_to: localhost
run_once: true

28
ansible/inventory.yml Normal file
View file

@ -0,0 +1,28 @@
nodes:
hosts:
proxmox-01:
ansible_host: 192.168.1.205
ansible_user: root
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
vms:
hosts:
mailer:
ansible_host: 192.168.1.36
ansible_user: plasmagoat
nas:
hosts:
nas-01:
ansible_host: 192.168.1.226
ansible_user: plasmagoat
ansible_ssh_private_key_file: ~/.ssh/id_ed25519
proxmox:
hosts:
proxmox-01:
# vms:
# hosts:
# tailgate:
# ansible_user: example
# ansible_host: example.example.ts.net

1
ansible/roles/common/files/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.key

View file

@ -0,0 +1,15 @@
- name: Ensure /etc/sops exists
file:
path: /etc/sops
state: directory
owner: root
group: root
mode: "0700"
- name: Upload age key
copy:
src: files/age.key
dest: /etc/sops/age.key
owner: root
group: root
mode: "0600"