initial commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthias Johnson 2026-02-27 15:09:25 -07:00
commit 75891c3271
129 changed files with 8046 additions and 0 deletions

87
playbooks/bootstrap.yml Normal file
View file

@ -0,0 +1,87 @@
---
- name: Bootstrap Ubuntu server
hosts: all
become: true
pre_tasks:
- name: Ensure apt cache is up to date
apt:
update_cache: true
cache_valid_time: 3600
tasks:
- name: Set timezone
timezone:
name: "{{ timezone }}"
- name: Create admin user
user:
name: "{{ admin_user }}"
groups: sudo
shell: "{{ admin_shell }}"
append: true
create_home: true
- name: Authorize SSH key for admin user
authorized_key:
user: "{{ admin_user }}"
key: "{{ admin_ssh_key }}"
- name: Disable root SSH login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
notify: restart ssh
- name: Disable password authentication
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PasswordAuthentication'
line: 'PasswordAuthentication no'
notify: restart ssh
- name: Install base packages
apt:
name:
- ca-certificates
- curl
- git
- tmux
- neovim
- ripgrep
- fd-find
- zsh
- ufw
- fail2ban
- rclone
- bat
- lsb-release
- rsync
state: present
- name: Enable UFW
ufw:
state: enabled
policy: deny
- name: Allow SSH
ufw:
rule: allow
port: 22
proto: tcp
- name: Enable fail2ban
systemd:
name: fail2ban
enabled: true
state: started
handlers:
- name: restart ssh
service:
name: ssh
state: restarted
roles:
- role: docker

7
playbooks/caddy.yml Normal file
View file

@ -0,0 +1,7 @@
---
- name: Deploy Caddy
hosts: all
become: true
roles:
- caddy

8
playbooks/diun.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Deploy Diun (Docker Image Update Notifier)
hosts: all
become: true
roles:
- role: diun
when: enable_diun | default(true)

23
playbooks/dns.yml Normal file
View file

@ -0,0 +1,23 @@
---
# Manage DNS zones on Hetzner Cloud
#
# Zone definitions live in $LINDERHOF_DIR/group_vars/all/dns.yml
# (generated from inventory/group_vars/all/dns.yml.setup by setup.sh).
#
# To add DKIM keys after first mail deployment:
# docker exec mailserver cat /tmp/docker-mailserver/rspamd/dkim/<domain>/mail.pub
# Then add to vault.yml:
# ansible-vault edit $LINDERHOF_DIR/group_vars/all/vault.yml
# dkim_keys:
# example.com: "v=DKIM1; k=rsa; p=..."
# And uncomment the mail._domainkey record in dns.yml.
#
# Usage: ansible-playbook playbooks/dns.yml
- name: Manage DNS zones on Hetzner Cloud
hosts: localhost
connection: local
gather_facts: false
roles:
- role: dns
tags: dns

8
playbooks/docker.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Install Docker and prepare filesystem
hosts: all
become: true
roles:
- docker
- docker_network

8
playbooks/fail2ban.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Setup fail2ban
hosts: all
become: true
roles:
- role: fail2ban
when: enable_fail2ban | default(true)

8
playbooks/forgejo.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Deploy Forgejo Git Server
hosts: all
become: true
roles:
- role: forgejo
when: enable_forgejo | default(true)

8
playbooks/goaccess.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Configure GoAccess Analytics
hosts: all
become: true
roles:
- role: goaccess
when: enable_goaccess | default(true)

8
playbooks/mail.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Mail server setup
hosts: all
become: true
roles:
- role: mail
when: enable_mail | default(true)

8
playbooks/monitoring.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Deploy monitoring stack
hosts: all
become: true
roles:
- role: monitoring
when: enable_monitoring | default(true)

8
playbooks/nebula.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Setup Nebula overlay network
hosts: all
become: true
roles:
- role: nebula
when: enable_nebula | default(false)

12
playbooks/provision.yml Normal file
View file

@ -0,0 +1,12 @@
---
# Provision a cloud VM
# Usage: ansible-playbook playbooks/provision.yml
# Override defaults: -e server_name=aspen -e hcloud_server_type=cpx21
- name: Provision cloud server
hosts: localhost
connection: local
gather_facts: false
roles:
- role: provision
tags: provision

8
playbooks/radicale.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Deploy Radicale (CalDAV/CardDAV)
hosts: all
become: true
roles:
- role: radicale
when: enable_radicale | default(true)

8
playbooks/restic.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Configure Restic Backups
hosts: all
become: true
roles:
- role: restic
when: enable_restic | default(true)

46
playbooks/site.yml Normal file
View file

@ -0,0 +1,46 @@
---
# Master playbook - runs all components in order
# Usage: ansible-playbook playbooks/site.yml
#
# To run specific components, use tags:
# ansible-playbook playbooks/site.yml --tags mail
# ansible-playbook playbooks/site.yml --tags monitoring,restic
- import_playbook: bootstrap.yml
tags: [bootstrap, never] # only runs when explicitly tagged
- import_playbook: docker.yml
tags: [docker]
- import_playbook: nebula.yml
tags: [nebula]
- import_playbook: caddy.yml
tags: [caddy]
- import_playbook: mail.yml
tags: [mail]
- import_playbook: forgejo.yml
tags: [forgejo]
- import_playbook: monitoring.yml
tags: [monitoring]
- import_playbook: tuwunel.yml
tags: [tuwunel]
- import_playbook: radicale.yml
tags: [radicale]
- import_playbook: diun.yml
tags: [diun]
- import_playbook: restic.yml
tags: [restic]
- import_playbook: fail2ban.yml
tags: [fail2ban]
- import_playbook: goaccess.yml
tags: [goaccess]

8
playbooks/tuwunel.yml Normal file
View file

@ -0,0 +1,8 @@
---
- name: Deploy Tuwunel Matrix Server
hosts: all
become: true
roles:
- role: tuwunel
when: enable_tuwunel | default(true)