add homekeeper stack

This commit is contained in:
2026-07-06 19:25:38 +02:00
commit 58983e6855
90 changed files with 6816 additions and 0 deletions
@@ -0,0 +1,45 @@
---
- name: Upgrade all packages
apt:
update_cache: true
upgrade: dist
cache_valid_time: 3600
- name: Install base packages
apt:
name:
- curl
- git
- ufw
- fail2ban
- unattended-upgrades
- ca-certificates
state: present
- name: Configure ufw — allow SSH
ufw:
rule: allow
name: OpenSSH
- name: Configure ufw — allow HTTP
ufw:
rule: allow
port: "80"
proto: tcp
- name: Configure ufw — allow HTTPS
ufw:
rule: allow
port: "443"
proto: tcp
- name: Enable ufw
ufw:
state: enabled
policy: deny
- name: Enable unattended-upgrades
service:
name: unattended-upgrades
enabled: true
state: started
+26
View File
@@ -0,0 +1,26 @@
---
- name: Create Gitea quadlet directory
file:
path: /etc/containers/systemd
state: directory
mode: "0755"
- name: Deploy Gitea container quadlet
template:
src: gitea.container.j2
dest: /etc/containers/systemd/gitea.container
mode: "0644"
notify:
- Reload systemd
- Restart gitea
handlers:
- name: Reload systemd
systemd:
daemon_reload: true
- name: Restart gitea
systemd:
name: gitea
state: restarted
enabled: true
@@ -0,0 +1,23 @@
[Unit]
Description=Gitea — Git service and container registry
After=network-online.target
[Container]
Image=docker.io/gitea/gitea:latest
ContainerName=gitea
PublishPort=127.0.0.1:{{ gitea_http_port }}:3000
Volume={{ gitea_data_dir }}:/data:Z
Environment=USER_UID=1000
Environment=USER_GID=1000
Environment=GITEA__server__DOMAIN={{ gitea_domain }}
Environment=GITEA__server__ROOT_URL=https://{{ gitea_domain }}/
Environment=GITEA__server__HTTP_PORT=3000
Environment=GITEA__packages__ENABLED=true
Environment=GITEA__packages__CHUNKED_UPLOAD_PATH=/data/tmp/package-upload
[Service]
Restart=always
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target default.target
@@ -0,0 +1,43 @@
---
- name: Create quadlet directory
file:
path: /etc/containers/systemd
state: directory
mode: "0755"
- name: Deploy homekeeper network quadlet
template:
src: homekeeper.network.j2
dest: /etc/containers/systemd/homekeeper.network
mode: "0644"
notify: Reload systemd
- name: Deploy container quadlets
template:
src: "{{ item }}.j2"
dest: "/etc/containers/systemd/{{ item }}"
mode: "0644"
loop:
- homekeeper-db.container
- homekeeper-api.container
- homekeeper-beekeeper.container
- homekeeper-listkeeper.container
notify:
- Reload systemd
- Restart homekeeper
handlers:
- name: Reload systemd
systemd:
daemon_reload: true
- name: Restart homekeeper
systemd:
name: "{{ item }}"
state: restarted
enabled: true
loop:
- homekeeper-db
- homekeeper-api
- homekeeper-beekeeper
- homekeeper-listkeeper
@@ -0,0 +1,25 @@
[Unit]
Description=Homekeeper — FastAPI
After=network-online.target homekeeper-db.service
[Container]
Image={{ registry_host }}/{{ registry_user }}/homekeeper-api:latest
ContainerName=homekeeper-api
Network=homekeeper.network
PublishPort=127.0.0.1:8000:8000
Environment=DB_HOST=homekeeper-db
Environment=DB_PORT=5432
Environment=DB_NAME={{ db_name }}
Environment=DB_USER={{ db_user }}
Environment=DB_PASSWORD={{ db_password }}
Environment=ROOT_PATH=/api
Environment=INITIAL_USERS={{ initial_users }}
AutoUpdate=registry
Label=io.containers.autoupdate=registry
[Service]
Restart=always
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target default.target
@@ -0,0 +1,21 @@
[Unit]
Description=Homekeeper — Beekeeper (Shiny)
After=network-online.target homekeeper-api.service
[Container]
Image={{ registry_host }}/{{ registry_user }}/homekeeper-beekeeper:latest
ContainerName=homekeeper-beekeeper
Network=homekeeper.network
PublishPort=127.0.0.1:3838:3838
Environment=API_URL=http://homekeeper-api:8000
Environment=API_USER={{ api_user }}
Environment=API_PASS={{ api_pass }}
AutoUpdate=registry
Label=io.containers.autoupdate=registry
[Service]
Restart=always
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target default.target
@@ -0,0 +1,23 @@
[Unit]
Description=Homekeeper — PostgreSQL
After=network-online.target
[Container]
Image=docker.io/library/postgres:17
ContainerName=homekeeper-db
Network=homekeeper.network
Volume={{ homekeeper_data_dir }}/pg_data:/var/lib/postgresql/data:Z
Environment=POSTGRES_DB={{ db_name }}
Environment=POSTGRES_USER={{ db_user }}
Environment=POSTGRES_PASSWORD={{ db_password }}
HealthCmd=pg_isready -U {{ db_user }} -d {{ db_name }}
HealthInterval=5s
HealthRetries=10
# No AutoUpdate — avoid surprise postgres major-version upgrades
[Service]
Restart=always
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target default.target
@@ -0,0 +1,22 @@
[Unit]
Description=Homekeeper — Listkeeper (Shiny)
After=network-online.target homekeeper-api.service
[Container]
Image={{ registry_host }}/{{ registry_user }}/homekeeper-listkeeper:latest
ContainerName=homekeeper-listkeeper
Network=homekeeper.network
PublishPort=127.0.0.1:3839:3839
Environment=PORT=3839
Environment=API_URL=http://homekeeper-api:8000
Environment=API_USER={{ api_user }}
Environment=API_PASS={{ api_pass }}
AutoUpdate=registry
Label=io.containers.autoupdate=registry
[Service]
Restart=always
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target default.target
@@ -0,0 +1,2 @@
[Network]
Driver=bridge
+50
View File
@@ -0,0 +1,50 @@
---
- name: Install nginx and certbot
apt:
name:
- nginx
- certbot
- python3-certbot-nginx
state: present
update_cache: true
- name: Remove default nginx site
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload nginx
- name: Deploy homekeeper nginx config
template:
src: homekeeper.conf.j2
dest: /etc/nginx/sites-available/homekeeper.conf
mode: "0644"
notify: Reload nginx
- name: Enable homekeeper nginx site
file:
src: /etc/nginx/sites-available/homekeeper.conf
dest: /etc/nginx/sites-enabled/homekeeper.conf
state: link
notify: Reload nginx
- name: Obtain Let's Encrypt certificates
command: >
certbot --nginx -d {{ domain }} -d {{ gitea_domain }}
--non-interactive --agree-tos -m {{ gitea_admin_email }}
--redirect
args:
creates: /etc/letsencrypt/live/{{ domain }}/fullchain.pem
notify: Reload nginx
- name: Enable nginx
service:
name: nginx
enabled: true
state: started
handlers:
- name: Reload nginx
service:
name: nginx
state: reloaded
@@ -0,0 +1,77 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# ── Main app: friessn.de ────────────────────────────────────────────────────
server {
listen 80;
server_name {{ domain }};
# certbot --nginx adds SSL redirect + listen 443 block here
root /var/www/html;
index index.html;
location = / {
try_files /index.html =404;
}
location = /api { return 301 /api/; }
location /api/ {
rewrite ^/api/(.*) /$1 break;
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /beekeeper { return 301 /beekeeper/; }
location /beekeeper/ {
rewrite ^/beekeeper/(.*) /$1 break;
proxy_pass http://127.0.0.1:3838;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
location = /listkeeper { return 301 /listkeeper/; }
location /listkeeper/ {
rewrite ^/listkeeper/(.*) /$1 break;
proxy_pass http://127.0.0.1:3839;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
# ── Gitea: git.friessn.de ───────────────────────────────────────────────────
server {
listen 80;
server_name {{ gitea_domain }};
# certbot --nginx adds SSL redirect + listen 443 block here
client_max_body_size 512m;
location / {
proxy_pass http://127.0.0.1:{{ gitea_http_port }};
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
@@ -0,0 +1,59 @@
---
- name: Install podman
apt:
name:
- podman
- podman-compose # for ad-hoc use; production uses quadlets
state: present
update_cache: true
- name: Create homekeeper data directories
file:
path: "{{ item }}"
state: directory
mode: "0750"
loop:
- "{{ homekeeper_data_dir }}"
- "{{ homekeeper_data_dir }}/pg_data"
- "{{ gitea_data_dir }}"
- name: Configure Gitea as additional registry
template:
src: registries.conf.j2
dest: /etc/containers/registries.conf.d/gitea.conf
mode: "0644"
notify: Restart podman services
- name: Login to Gitea container registry
command: >
podman login {{ registry_host }}:{{ registry_port }}
-u {{ registry_user }} -p {{ registry_token }}
register: login_result
changed_when: "'Login Succeeded' in login_result.stdout"
# Run this after Gitea is up and registry_token is set
- name: Enable podman-auto-update timer
systemd:
name: podman-auto-update.timer
enabled: true
state: started
daemon_reload: true
- name: Override auto-update timer schedule
copy:
dest: /etc/systemd/system/podman-auto-update.timer.d/override.conf
content: |
[Timer]
OnCalendar=
OnCalendar={{ autoupdate_schedule }}
AccuracySec=1s
mode: "0644"
notify: Reload systemd
handlers:
- name: Reload systemd
systemd:
daemon_reload: true
- name: Restart podman services
command: systemctl daemon-reload
@@ -0,0 +1,3 @@
[[registry]]
location = "{{ registry_host }}:{{ registry_port }}"
insecure = false