40 changed files with 46 additions and 939 deletions
-1
View File
@@ -62,7 +62,6 @@ homelab-v2/
| **Archmirror** | Local Arch Linux package repository mirror | | **Archmirror** | Local Arch Linux package repository mirror |
| **Blog** | Personal static blog served via git-sync + nginx (gh-pages branch) | | **Blog** | Personal static blog served via git-sync + nginx (gh-pages branch) |
| **Vikunja** | To-do list and task management, SSO via Authelia OIDC | | **Vikunja** | To-do list and task management, SSO via Authelia OIDC |
| **Reitti** | Personal location history and timeline (PostGIS), SSO via Authelia OIDC |
## Infrastructure Stack ## Infrastructure Stack
@@ -41,9 +41,6 @@ spec:
value: ":514" value: ":514"
useRemoteIP: true useRemoteIP: true
useLocalTimestamp: true useLocalTimestamp: true
# Scraped by the stack's vmagent so ingestion stalls can alert.
vmServiceScrape:
enabled: true
resources: resources:
requests: requests:
cpu: 50m cpu: 50m
@@ -59,49 +59,10 @@ spec:
vmalert: vmalert:
enabled: true enabled: true
# k3s runs scheduler/controller-manager in one binary with no separate # Telegram + email wired later (see monitoring-rpi5-setup.md step 11).
# scrape endpoints, and uses kine instead of etcd — disabling these drops # Default config uses a blackhole receiver until then.
# the empty scrape pools and their always-firing rules.
kubeScheduler:
enabled: false
kubeControllerManager:
enabled: false
kubeEtcd:
enabled: false
alertmanager: alertmanager:
enabled: true enabled: true
spec:
# Mounted at /etc/vm/secrets/alertmanager-telegram/ (bot_token, chat_id).
secrets:
- alertmanager-telegram
config:
route:
receiver: telegram
group_by: ["alertname", "job"]
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
routes:
- receiver: blackhole
matchers:
- alertname=~"Watchdog|InfoInhibitor"
- receiver: blackhole
matchers:
- severity="info"
inhibit_rules:
- source_matchers:
- severity="critical"
target_matchers:
- severity="warning"
equal: ["alertname", "job"]
receivers:
- name: blackhole
- name: telegram
telegram_configs:
- bot_token_file: /etc/vm/secrets/alertmanager-telegram/bot_token
chat_id_file: /etc/vm/secrets/alertmanager-telegram/chat_id
send_resolved: true
grafana: grafana:
enabled: true enabled: true
@@ -1,24 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: alertmanager-telegram
namespace: monitoring
type: Opaque
stringData:
bot_token: ENC[AES256_GCM,data:V/SDGyp/M7Qqa22fiKYMZ2CzkivNBl24hv9cVEFPl50NySKY0jqIPnVWLtm11g==,iv:UfHMfvu9b2CaXhImng5OLVej13zHrptKQOaPUbjXiw0=,tag:SFAGUaM0XYvbVc1CRrJepQ==,type:str]
chat_id: ENC[AES256_GCM,data:HRDHrCMMurk=,iv:hP7UB23qWZ+YukoP3B7QolUIfv2FgJtTfM1OLe/nMMY=,tag:JTwjQwDLQaG5LfKQGV73iw==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwNXF4V1N3bmpxbWN5YUVR
UDNNdm1IL2hHWGgzRENvK0xWdkhFc1drRGhBCjdQc3hydG1RN3ZocUZnZGpKRG5i
K1RXUTdiZ29hWWdjLzZVMCtMb1NZbjQKLS0tIHpDcTNDeFpJUU5CeU5PSFNWWnBo
UmJNT1hVL0h3c3hWOGQxM21uWk14amsKIyFxmszp94FteSUXyAh4hrDNbPBja4dT
QL6wFw8GkYtFeucIgnvbjHWWi98QMwE1xEt930uMeNyRnLFqFfUtWw==
-----END AGE ENCRYPTED FILE-----
recipient: age1jetw4h63gq4uzyk08znynw4h852nexdmtkdz4kwxj5ew5st32vnspmtag2
encrypted_regex: ^(data|stringData|email)$
lastmodified: "2026-10-03T20:07:21Z"
mac: ENC[AES256_GCM,data:k7rBxhWrC2DFvFcoB6Wqufzk6vLtWFypITl/JK2qd6Vj9m7XKBZdiH5mCSDNfo4UK+ygFnGQ8oidkgcCrbGYqKFK8Q67+LQ9o1OMOXcZDkz6UzNRaLh3aO5NqbdleV36cICX6qpG1uO6GL6p5g121vRztQT+Qg1L0BkIMrF+sJQ=,iv:y8figgbzUg1gf0zug534Fvd9jdB00JiA7LoWXUm3/Lw=,tag:ccP3IKdWwMIJqP0s/U7NQA==,type:str]
version: 3.13.3
@@ -1,36 +0,0 @@
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMRule
metadata:
name: homelab
namespace: monitoring
spec:
groups:
- name: unifi-gateway
rules:
# Baseline load is 2–5; the 2026-09-26 memory-pressure incident sat at 15–25.
- alert: UnifiGatewayHighLoad
expr: avg_over_time(unpoller_device_load_average_1{type="udm"}[15m]) > 10
for: 15m
labels:
severity: warning
annotations:
summary: "UniFi gateway load is {{ $value | humanize }} (15m avg)"
# Baseline is 84–92% and creeps up ~1%/3 days until something restarts.
- alert: UnifiGatewayMemoryHigh
expr: avg_over_time(unpoller_device_memory_utilization_ratio{type="udm"}[30m]) > 0.93
for: 30m
labels:
severity: warning
annotations:
summary: "UniFi gateway memory at {{ $value | humanizePercentage }} (30m avg)"
- name: victoria-logs
rules:
# The gateway alone logs DHCP chatter every few minutes, so zero rows
# means the syslog path is broken (e.g. the 2026-09-22 IP change).
- alert: SyslogIngestionStalled
expr: sum(rate(vl_rows_ingested_total{type="syslog_udp"}[30m])) == 0
for: 15m
labels:
severity: warning
annotations:
summary: "VictoriaLogs has received no syslog for 45m"
+1 -1
View File
@@ -26,7 +26,7 @@ spec:
image: image:
# renovate: datasource=docker depName=fireflyiii/core # renovate: datasource=docker depName=fireflyiii/core
tag: version-6.7.7 tag: version-6.6.6
podSecurityContext: podSecurityContext:
seccompProfile: seccompProfile:
+3 -3
View File
@@ -199,11 +199,11 @@ spec:
type: RuntimeDefault type: RuntimeDefault
image: image:
# renovate: currentValue=28.1.0-rootless currentDigest=sha256:b1a90409ae9afcd5a5725404c3639da7245248848b99e35332968891290b953e # renovate: currentValue=1.27.3-rootless currentDigest=sha256:1c17ecaead42eb3b5391553d8708103a4beb0e86edf5b9ebc1eb269c318845f2
tag: 28.1.0 tag: 1.27.3
digest: sha256:b1a90409ae9afcd5a5725404c3639da7245248848b99e35332968891290b953e digest: sha256:1c17ecaead42eb3b5391553d8708103a4beb0e86edf5b9ebc1eb269c318845f2
rootless: true rootless: true
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
+1 -3
View File
@@ -25,10 +25,8 @@ spec:
- sh - sh
- -c - -c
- | - |
set -e
apk add --no-cache sqlite apk add --no-cache sqlite
sqlite3 "file:/db-local/grocy.db?mode=ro" ".backup /backup/grocy.db" sqlite3 /db-local/grocy.db ".backup /backup/grocy.db"
[ "$(sqlite3 /backup/grocy.db 'PRAGMA integrity_check')" = ok ]
volumeMounts: volumeMounts:
- name: db - name: db
mountPath: /db-local mountPath: /db-local
-5
View File
@@ -24,7 +24,6 @@ data:
type: jellyfin type: jellyfin
url: https://${JELLYFIN_HOST} url: https://${JELLYFIN_HOST}
key: "{{HOMEPAGE_VAR_JELLYFIN_API_KEY}}" key: "{{HOMEPAGE_VAR_JELLYFIN_API_KEY}}"
version: 2 # Jellyfin 12 dropped /emby paths and ?api_key auth
enableBlocks: true enableBlocks: true
enableUser: true enableUser: true
enableMediaControl: false enableMediaControl: false
@@ -95,10 +94,6 @@ data:
icon: vikunja.png icon: vikunja.png
href: https://${VIKUNJA_HOST}/ href: https://${VIKUNJA_HOST}/
description: Task management description: Task management
- Reitti:
icon: mdi-map-marker-path
href: https://${REITTI_HOST}/
description: Location history
widgets.yaml: | widgets.yaml: |
--- ---
+1 -1
View File
@@ -24,7 +24,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: homepage - name: homepage
image: ghcr.io/gethomepage/homepage:v2.4.0 image: ghcr.io/gethomepage/homepage:v2.3.0
ports: ports:
- containerPort: 3000 - containerPort: 3000
name: http name: http
+1 -1
View File
@@ -28,7 +28,7 @@ spec:
main: main:
image: image:
repository: ghcr.io/immich-app/immich-server repository: ghcr.io/immich-app/immich-server
tag: v3.2.4 tag: v3.2.0
resources: resources:
requests: requests:
cpu: 100m cpu: 100m
+5 -13
View File
@@ -5,11 +5,6 @@
# The volume is mounted read-write on purpose: jellyfin.db is in WAL mode, and # The volume is mounted read-write on purpose: jellyfin.db is in WAL mode, and
# SQLite cannot open a WAL database from a read-only filesystem once Jellyfin has # SQLite cannot open a WAL database from a read-only filesystem once Jellyfin has
# closed it and removed the -wal/-shm files (e.g. while scaled to zero). # closed it and removed the -wal/-shm files (e.g. while scaled to zero).
# The connection itself is read-only (?mode=ro). A read-write connection that
# believes it is the last one checkpoints and deletes -wal/-shm on close; when
# Jellyfin had lost its POSIX locks this deleted them under the running server
# and corrupted jellyfin.db (2026-09-16). The copy is integrity-checked so a
# broken snapshot fails the job instead of landing in restic.
apiVersion: batch/v1 apiVersion: batch/v1
kind: CronJob kind: CronJob
metadata: metadata:
@@ -39,8 +34,7 @@ spec:
- | - |
set -e set -e
apk add --no-cache sqlite apk add --no-cache sqlite
sqlite3 "file:/db-local/jellyfin.db?mode=ro" ".backup /backup/jellyfin.db" sqlite3 /db-local/jellyfin.db ".backup /backup/jellyfin.db"
[ "$(sqlite3 /backup/jellyfin.db 'PRAGMA integrity_check')" = ok ]
volumeMounts: volumeMounts:
- name: db - name: db
mountPath: /db-local mountPath: /db-local
@@ -48,7 +42,7 @@ spec:
mountPath: /backup mountPath: /backup
containers: containers:
- name: resticprofile - name: resticprofile
image: creativeprojects/resticprofile:0.32.0 image: creativeprojects/resticprofile:0.33.1
command: command:
- sh - sh
- -c - -c
@@ -90,8 +84,7 @@ spec:
# media files and the metadata providers. # media files and the metadata providers.
# Intro Skipper keeps its results in two live WAL-mode SQLite databases, so they # Intro Skipper keeps its results in two live WAL-mode SQLite databases, so they
# are snapshotted with sqlite3 ".backup" rather than copied as files (which could # are snapshotted with sqlite3 ".backup" rather than copied as files (which could
# capture a torn page mid-write). Read-write mount and read-only connection for # capture a torn page mid-write). Read-write mount for the same reason as above.
# the same reasons as above.
apiVersion: batch/v1 apiVersion: batch/v1
kind: CronJob kind: CronJob
metadata: metadata:
@@ -123,8 +116,7 @@ spec:
apk add --no-cache sqlite apk add --no-cache sqlite
mkdir -p /backup/introskipper mkdir -p /backup/introskipper
for db in introskipper.db introskipper-cache.db; do for db in introskipper.db introskipper-cache.db; do
sqlite3 "file:/config/data/introskipper/$db?mode=ro" ".backup /backup/introskipper/$db" sqlite3 "/config/data/introskipper/$db" ".backup /backup/introskipper/$db"
[ "$(sqlite3 "/backup/introskipper/$db" 'PRAGMA integrity_check')" = ok ]
done done
volumeMounts: volumeMounts:
- name: config - name: config
@@ -133,7 +125,7 @@ spec:
mountPath: /backup mountPath: /backup
containers: containers:
- name: resticprofile - name: resticprofile
image: creativeprojects/resticprofile:0.32.0 image: creativeprojects/resticprofile:0.33.1
command: command:
- sh - sh
- -c - -c
+1 -1
View File
@@ -43,7 +43,7 @@ spec:
mountPath: /db-local mountPath: /db-local
containers: containers:
- name: jellyfin - name: jellyfin
image: jellyfin/jellyfin:12.2 image: jellyfin/jellyfin:12.0
env: env:
- name: JELLYFIN_PublishedServerUrl - name: JELLYFIN_PublishedServerUrl
value: https://${JELLYFIN_HOST} value: https://${JELLYFIN_HOST}
+1 -1
View File
@@ -129,7 +129,7 @@ spec:
mountPath: /backup mountPath: /backup
containers: containers:
- name: resticprofile - name: resticprofile
image: creativeprojects/resticprofile:0.32.0 image: creativeprojects/resticprofile:0.33.1
command: command:
- sh - sh
- -c - -c
@@ -45,7 +45,7 @@ spec:
- psql -d postgres -c 'CREATE DATABASE "prowlarr-log"' || true - psql -d postgres -c 'CREATE DATABASE "prowlarr-log"' || true
containers: containers:
- name: prowlarr - name: prowlarr
image: lscr.io/linuxserver/prowlarr:2.6.5 image: lscr.io/linuxserver/prowlarr:2.5.2
envFrom: envFrom:
- configMapRef: - configMapRef:
name: media-common-env name: media-common-env
@@ -29,7 +29,7 @@ spec:
mountPath: /media mountPath: /media
containers: containers:
- name: qbittorrent - name: qbittorrent
image: lscr.io/linuxserver/qbittorrent:5.2.4 image: lscr.io/linuxserver/qbittorrent:5.2.3
envFrom: envFrom:
- configMapRef: - configMapRef:
name: media-common-env name: media-common-env
+1 -1
View File
@@ -54,7 +54,7 @@ spec:
- psql -d postgres -c 'CREATE DATABASE "radarr-log"' || true - psql -d postgres -c 'CREATE DATABASE "radarr-log"' || true
containers: containers:
- name: radarr - name: radarr
image: lscr.io/linuxserver/radarr:6.4.4 image: lscr.io/linuxserver/radarr:6.3.0
envFrom: envFrom:
- configMapRef: - configMapRef:
name: media-common-env name: media-common-env
+1 -1
View File
@@ -54,7 +54,7 @@ spec:
- psql -d postgres -c 'CREATE DATABASE "sonarr-log"' || true - psql -d postgres -c 'CREATE DATABASE "sonarr-log"' || true
containers: containers:
- name: sonarr - name: sonarr
image: lscr.io/linuxserver/sonarr:4.0.20 image: lscr.io/linuxserver/sonarr:4.0.19
envFrom: envFrom:
- configMapRef: - configMapRef:
name: media-common-env name: media-common-env
+1 -1
View File
@@ -18,7 +18,7 @@ spec:
targetNamespace: media targetNamespace: media
values: values:
image: image:
tag: v3.5.0 tag: v3.4.1
podLabels: podLabels:
app: seerr app: seerr
extraEnv: extraEnv:
+1 -1
View File
@@ -24,7 +24,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: paperless - name: paperless
image: ghcr.io/paperless-ngx/paperless-ngx:3.3 image: ghcr.io/paperless-ngx/paperless-ngx:3.1
ports: ports:
- containerPort: 8000 - containerPort: 8000
name: http name: http
+2 -2
View File
@@ -27,7 +27,7 @@ spec:
mountPath: /data mountPath: /data
containers: containers:
- name: pihole - name: pihole
image: pihole/pihole:2026.07.2 image: pihole/pihole:2026.02.0
envFrom: envFrom:
- configMapRef: - configMapRef:
name: pihole-config name: pihole-config
@@ -95,7 +95,7 @@ spec:
mountPath: /data mountPath: /data
- name: dnscrypt-proxy - name: dnscrypt-proxy
image: klutchell/dnscrypt-proxy:v2.1.18 image: klutchell/dnscrypt-proxy:v2.1.15
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
env: env:
- name: TZ - name: TZ
+9 -9
View File
@@ -4,19 +4,19 @@ metadata:
name: podsync-config name: podsync-config
namespace: podsync namespace: podsync
data: data:
config.toml: ENC[AES256_GCM,data:MvMimo9Cn94BXQzCQqnlt3z0aSzoDwq5t2I9OHXATGuX2+q7lTksBMh3Vz5CHm5YY9xvXtPqO5kRPtoYuaDwvsM3vWe9zXclThJOQJqND/haV188yvoDw1jCWe7a2zGQ3SsgpJYBncZJ44/cMYn9mWj7wXdUegFOFfi/4g+xGBZ2c4aQmJAD5lHz3PJW9WrDYqlfBbX8Ipt1OQtZd1FKHSTmbifqvzoLv34qUKxz/LY9RiFOpBNXRhH53aDRpiMuHdtl4I9eFZi4B/EXqhdFZXLCTAKMi2bDT2xSHkefAfexvyHzV0Uv2z+ZWdzuUua/S17JHkA53sIxMk60bkE9VU8JDuStqRGj1kZy7dgGoKZceuK7O7SF9RMj6f/zsnmAYhye65T0EziK764TqEMibOL/tgfOMSmQcEae4+YzuD9KepTe0sLjowFRfb7fwCHMU/AO96u0HyWx67mrZwPMCyffCPIZDKPflQ+qPpmcSqGHJ7q7TBiPyPApv/Vp/91oULuwPLlgY7ovLvfV5xsjzKkeFHsYB2G+rgG2qGMvykAwtGaoD65/Cm4PG6rqy9pUKEy3yU+cX6ie2uX1aAKBsBSMgZsT9+fK7Eh/Oq/O9jwiCbDztEQ0CpSAVxwHDEwHa5ibCDFCSw92/JKEu/wy8Mt5xzeXbZt9t9tgB2jrZlYUfRNqlPPjYsLAd4WLSlovqKg7qkn6u96tXaMAagdSXu7P4Su4GjMljai4az5FQRUoIC6t6aPa9pIU+JHmI/UzX6dnrX7RygkfIFZyl2llpmtoICKOZkA58/3arzebkrcpASWn4g3gNIEFUa6Cxev9WAk557LLybJ4bc9meqyZfagsCATk2HfAaVMWvWu+Ul3w2DaXoklbOPlT1Mn+WtpHT1h6wj0h7JDz+WYA88Bk9f+aAxPPSv+JE6lEzrnCtPxFHpNmN6iSvX36S6ZKAJO/djDkHt/A2D52mme6j1GGfwZ3UtKACgDEV6fvw+Rcedu3O9IvyzOQZwxOODasIN4nhPzfyhXvHQT9sjZSMIYoKIlfVEylfEEHtlc3eHc18WUMpFJROUuteDmiAalD+swNBNZ6xEv2KTjkK3kSMvbdkC0ZyFZf43D72JCLwHK4Pcn3vFUeXQ3pZVjSTSnDntcs6HPJvBywxQqUmj02zks47TfOVcdWGSeZ2hmyTqrQfHD/n5ChO2yp0629CqlGtBfnQht+tUo7vnUNiY1+vbCHzAi3D4mBCQs4ftOvPqbWmN/s1NbPG9+TR/BricGoRTr5nNrlgtRBA8DEldpQjEyvrtIEoS/qgKeNFOVBqs8mHBr0fnk4ZQgMJx2KOPxcG210xfvQOOmhUHbdo1fF7K430TsI/PszN2QsI8MgmSoLp0CoeQWdVzWiGbOyww6vdYMgstELWE9YVrr+EXIp2lcwvIZFDApRx9PofArUNEGIiOQJ9BLR9QjFiicLXboz/l6XuQov4nnLJc9oL7Jfyv3zjbnCzzhwFN+bs0RjaBqEv7uA6BAnPre7tSwKqNjTwyPu9DSffGiZFQdjtGZgYyxxGiMAqE++vj5eU8YVkVO9BO7sMfa4pl0GH7g6Lu7MSMv5B4MU79RTjr5E5n/LCIIcWF8PE963NATScK+rh8BmEC6tm3VQ4FFAT+wwX8vGlBIFJ0Xr0hpgr6tnKD9vFMx+wHEvJEydQZgDDmmOyOWHe+eNWdJxSTZBSrteGx62HysjeA0Xivb9dH5qgF/UDNNNDFjrAqyEALfke+XTOX9PkvOwP7S+RcfkfNH2pIALYksSox8+CSUrEfSffFmywn7mrGP5moFHod3kHQumF+/HLAlP6AvU+J1WNrXggNn85mPcFuHhR8tW5JNpvUpDhVzM7Jzb+4ZM3y6ZE3Dk+cdrfBntdh6p6i3VIfX0/pmm8hgzbKn/V77SYEkUaX0n7pjyjYrRMoGOh7qOjKWgxla48LthD4JS8qxIMpmbMy6z1Fy5PY3/gFJ7ATmKgdj2UgB5Wy/48P18HQZ665gnInBLpY01f59XaCVCoPZ0oszzht4Xcyl7mW3a5voh4DTqtKcrPlVKC7Acjuobi16/gtUUOwsCR0AQa9XTqT+yvX0rZwG0TNeLWBOchWX1HGFrrGN/m2GY5LmSXmcIfTb0KVy7ufQWblnbLxmUSvhwtbu2hwc466B2NFijlqJd3fi4Tz9xRdX0JJj0BV4A75agqg==,iv:ArCBeoyoh0RvuQSQ9W6RNF83T5ukZzBUaMZ5QIX9Jmw=,tag:7FFKbTG3iWeADE5fWdo25w==,type:str] config.toml: ENC[AES256_GCM,data:4C8zSvWM9kMxII0RU9EhfUvQGgZMJTtMUOVM9LGunfpkmZQjH3IrbsytgzZBbw7ha7IHjhLxvdXleHNXbc2ZCbphp/lhIrqOLsa2f8J/P/ppyJVLafEt+bQB4lVXVauhy72bV/9RZYIgCatDYMR7+sJVWGyl1f6ZnJ3S+nVXROXPmlxlDhJnCwPUVj+OVq7OKnDjspZpnlZizr5tRzMMJPVuVTDi9cKDFHnoL2x7iINyzvJk8Wb4N+k481sY7isJ5BJyTno3RNKhcykL8cfZQunQ1mlBodvZiSph1gAxY3H3oljb2uB0Zf4J3FkpSCPkIQBpGec+NiQAjPRk5zot0VCZVvtAEL1UfctvhcnhbMwNQbEfdvewFXbIF6lwuatI/gd2+ICuas19n6luzwAfw+WGOHtEDbsIccl6l9lfphid7TotKs992LqBVL3BuCoGM4kqe/8QZc+iaw2VbjGxJhim9T0NnvvPlj8WJ/hnOy+e4wLmzKZcryUNjqQdpzlPr/CFwlnKgU26zjyb6438vf0mC06Mp1AHCoqznZkLPOeJC7YeEybf0T2Dm1/7e0iBFVFVSX3zCUQ0fS1vCyulszUUNsJtAsgg/KkqDSiqT6YWWsUaDZ5qbkcIsQNBFcQVX3Owm7x2tcppi9xYOCFfIDxAx0ugx6kKTf/4XfZ4yIRyUhIETny3P/4WoHCzIz6Hd65RaxbIwbyRz8U8mFbsDtk3o+7c/6UsX1uEFJjoFFlrOcy9ID1um8LXGxicB6VdrtNfwWiFq9Vwf+eHdKFMC5fSqtuSu/yDHKC8w2eb98IG9k0rf+4NHzRlxYPhCUs8YJsWJYpXC4tK8fPWLg7zuByf8nnUQ405Ga8ZvcuDQ9xDWFtMg8JJoZ1wODHIJiovIxNlZQmuxGrrpI5+S4CZKVjEVgD7GRXn3ewDVMk8Tdaf1iq0x09cxj52rgf3VxeOiVolrNJgzygePvYSxb30nsMpQSmmLCGCp5viJ0FhH6MuccJK9wmzJiEYuC5OkhGHaQLkAUDdroZTBDek/AQGzdu8J+NL+Qk3KuJ1ZQs1xgzpB74vqAdjAUUNzZlDw5hejv7enjstTjU1usy88Y8Lf1AORHiGcLzxpwjdeQQFsTuBqPVCHs7Nt9xYYk5nbv8wXM8Z7gk/+SMJayTOq5PDfLZNd530M1rMBIZ1HSBvYsAQvGVd91xjoMvMs04VCoGZcFZuurukx9Rh6U/5pm5roIXkmWHFp/2S3HfnBqEbQYbqrV5jXGQs6yIEQcRT91UY7csdnDL9fzlR37T21cOXfo2CrCzZyaTfGh+y6GusC9xg9qaBihno+PxOV++h80Nd5MsYSXIjaXTX8CioKaCMCToEXHzWUUsr+tHopMR0fG+QJAiZ2Fa7c5dYAU2EKkyfziuhGPSxHBxrc9W/0VjfB10Vf+iFVGCP2JEm99G7esQNh9kszSkyY2wOycUllqQO3eT9dHsSFdswq/bvKgkvQz0oOmJcubE1jvUn7YW8CF6KABlM5L/hi+ntcNc2YWLWqaNghOQsjCbpiqjdp6pejiM9g+3NbC7O2Z8Nf0zwgka7FRQXaJfl+FHFb3X2Qk4VGiinoK+EVCQX4CCD9EYK065jkdTpqDDESy1n4SUMIkE2iA==,iv:cpa826ZkBPSc/ZX4P6sJ5kgDXMfryd+d3UAsbfb7764=,tag:V3FERsM9ZfNO8TbHEsf86w==,type:str]
sops: sops:
age: age:
- enc: | - enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaVFQxWG40NEVzcVBVTmp0 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2QTBUbnNBcGFhYjNiNGRG
bXJrWlRmdW0vK0JaaytiamNrVGM0dG9lQkYwCldjSVQ3akhlbTNITUxvTEE1Z2pY T3JqdFY0dTIzWDA3OGNVUkoreVhONXVDeFVVCkR0amlYMThyejlPaWlPSkdGL0xy
WGFjQTBoT2w0aXFreFdwcVlVWlBhRGcKLS0tIDBYRnZaK2FkL0YwRkZZb2loRmQx YUN3VEhGajJoQjNiRVV5ckw0cE1JaTAKLS0tIDFSWnpWWVFxQ0VVY2U4bUFtTWVk
VkZOR2g4bWJQTlRudVoyU01KT3FVREkKgqZ3NJtwtWgYThwdOxrerzl0KlaS5Wve bkg3K01kWFl4ZWZuK21KRTIxUEhDUEEKPGWzrJlyZGNOsvrVhWKw56y8iAwrqDQK
QxiwAtIrK+zXp/JL0q4UEVs5duO8VnrlS8kc1LvxR+uDt9iVpAWyeg== OWJYIq0gt9NWfNBao8UpiuKJXU4SX01hW4fa1OEfGSDJAjNNxGpFVA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
encrypted_regex: ^(data|stringData|email)$ encrypted_regex: ^(data|stringData|email)$
lastmodified: "2026-09-16T20:20:54Z" lastmodified: "2026-06-22T19:19:33Z"
mac: ENC[AES256_GCM,data:DY3u/NKp/be29EqpFoWE8B+b6t2rjJ4yy+3iONYgG0o04o8FfAr4IsToncdN9p1SZNqtEyxTmogzazRxqp2eTe4TBBg+Uqnpl2yEWhj9+ESIUJs+2YoWHpnB97+VOHy9hN6jDtUWSoIH7B1E4O54u5dISiw35v5O1bEl4Oxk8fk=,iv:9tUIfbmnjJ1D7nDIYoTxtmtA9Wah5wNwnzeZQkNh2U4=,tag:FNYW90bX5zxTBEb5aRBskg==,type:str] mac: ENC[AES256_GCM,data:Rd0q5r8DA3I7rNNbv9t/5c1LD0Dm1897rGvqhi4l91g9KpSCxQFu0+z6cUH7yhLCopFSWCezQHnBYEGFEkESl04DYkAAj/+ntLSnAhfHijbZshCdHhzr+bxMInajVbDMJTs0DXm2moFMUpcpVn3EHC3UTr/kj/PDfsK9oXugIW0=,iv:ZmlXvPONTD2w+Agh5QqYr8DMMbAeM/QQuWRsFcrw728=,tag:IRoRIxkcQQQuLbG+ccTxuA==,type:str]
version: 3.13.3 version: 3.13.1
-144
View File
@@ -1,144 +0,0 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: reitti-db-backup
namespace: reitti
labels:
app: reitti-backup
spec:
schedule: "30 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
labels:
app: reitti-backup
spec:
restartPolicy: OnFailure
initContainers:
- name: pg-dump
image: postgis/postgis:17-3.5
imagePullPolicy: IfNotPresent
env:
- name: PGHOST
value: reitti-db
- name: PGUSER
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_USERNAME
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_PASSWORD
- name: PGDATABASE
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_DATABASE_NAME
command:
- sh
- -c
- pg_dump --clean --if-exists > /backup/dump.sql
volumeMounts:
- name: backup-tmp
mountPath: /backup
containers:
- name: resticprofile
image: creativeprojects/resticprofile:0.32.0
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
resticprofile -c /secrets/profiles.yaml -n reitti-db backup
resticprofile -c /secrets/profiles.yaml -n reitti-db copy
env:
- name: B2_ACCOUNT_ID
valueFrom:
secretKeyRef:
name: reitti-backup-config
key: B2_ACCOUNT_ID
- name: B2_ACCOUNT_KEY
valueFrom:
secretKeyRef:
name: reitti-backup-config
key: B2_ACCOUNT_KEY
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
- name: backup-tmp
mountPath: /backup
volumes:
- name: secrets
secret:
secretName: reitti-backup-config
- name: backup-tmp
emptyDir: {}
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: reitti-files-backup
namespace: reitti
labels:
app: reitti-backup
spec:
schedule: "30 3 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
metadata:
labels:
app: reitti-backup
spec:
restartPolicy: OnFailure
containers:
- name: resticprofile
image: creativeprojects/resticprofile:0.32.0
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
resticprofile -c /secrets/profiles.yaml -n reitti-files backup
resticprofile -c /secrets/profiles.yaml -n reitti-files copy
env:
- name: B2_ACCOUNT_ID
valueFrom:
secretKeyRef:
name: reitti-backup-config
key: B2_ACCOUNT_ID
- name: B2_ACCOUNT_KEY
valueFrom:
secretKeyRef:
name: reitti-backup-config
key: B2_ACCOUNT_KEY
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
- name: files
mountPath: /files
readOnly: true
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
memory: 1Gi
volumes:
- name: secrets
secret:
secretName: reitti-backup-config
- name: files
persistentVolumeClaim:
claimName: reitti-data
@@ -1,54 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: reitti-redis
namespace: reitti
labels:
app: reitti-redis
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: reitti-redis
template:
metadata:
labels:
app: reitti-redis
spec:
securityContext:
runAsNonRoot: true
runAsUser: 999 # redis user in the alpine image
runAsGroup: 999
seccompProfile:
type: RuntimeDefault
containers:
- name: redis
image: redis:7.4.11-alpine
imagePullPolicy: IfNotPresent
# Cache only — no persistence, so no PVC.
args: ["--save", "", "--appendonly", "no"]
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: data
mountPath: /data
livenessProbe:
tcpSocket:
port: 6379
periodSeconds: 30
readinessProbe:
tcpSocket:
port: 6379
periodSeconds: 10
resources:
requests:
cpu: 20m
memory: 32Mi
limits:
memory: 256Mi
volumes:
- name: data
emptyDir: {}
@@ -1,53 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: reitti-tile-cache
namespace: reitti
labels:
app: reitti-tile-cache
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: reitti-tile-cache
template:
metadata:
labels:
app: reitti-tile-cache
spec:
securityContext:
# nginx image starts as root (renders nginx.conf, binds :80) then drops workers to nginx
seccompProfile:
type: RuntimeDefault
containers:
- name: tile-cache
image: dedicatedcode/reitti-tile-cache:5.6.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
volumeMounts:
- name: cache
mountPath: /var/cache/nginx
livenessProbe:
httpGet:
port: 80
path: /health
periodSeconds: 30
readinessProbe:
httpGet:
port: 80
path: /health
periodSeconds: 10
resources:
requests:
cpu: 20m
memory: 64Mi
limits:
memory: 1Gi # keys_zone shared memory: 512m tiles + 128m panoramax
volumes:
- name: cache
persistentVolumeClaim:
claimName: reitti-tile-cache
-120
View File
@@ -1,120 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: reitti
namespace: reitti
labels:
app: reitti
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: reitti
template:
metadata:
labels:
app: reitti
spec:
securityContext:
# The image starts as root only to remap UID/GID and chown /data, then drops to
# reitti (1000). Running as 1000 directly skips that; the NFS subdir provisioner
# creates directories 0777, so /data is writable without a chown.
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: reitti
image: dedicatedcode/reitti:5.6.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
- name: ADVERTISE_URI
value: https://${REITTI_HOST}
- name: JAVA_OPTS
value: -XX:MaxRAMPercentage=75
- name: POSTGIS_HOST
value: reitti-db
- name: POSTGIS_USER
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_USERNAME
- name: POSTGIS_PASSWORD
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_PASSWORD
- name: POSTGIS_DB
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_DATABASE_NAME
- name: REDIS_HOST
value: reitti-redis
# Tiles are proxied server-side through /api/v1/tiles, so the in-cluster URL works.
- name: TILES_CACHE
value: http://reitti-tile-cache
# Authentication against Authelia over OIDC only (redirect URI /login/oauth2/code/oauth).
# Unknown Authelia users are auto-created as regular users. With local login disabled,
# the next SSO login clears the user's local password and syncs the username.
- name: OIDC_ENABLED
value: "true"
- name: OIDC_ISSUER_URI
value: https://auth.${AUTHELIA_DOMAIN}
- name: OIDC_CLIENT_ID
value: reitti
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: reitti-credentials
key: OIDC_CLIENT_SECRET
- name: OIDC_SCOPE
value: openid,profile,email
- name: OIDC_AUTHENTICATION_METHOD
value: client_secret_basic
- name: OIDC_SIGN_UP_ENABLED
value: "true"
- name: DISABLE_LOCAL_LOGIN
value: "true"
volumeMounts:
- name: data
mountPath: /data
startupProbe:
httpGet:
port: 8080
path: /actuator/health
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 30 # DB migrations on first start / upgrades
# Generous timeouts: large imports (Google Timeline, ~500k points) keep the JVM busy
# for minutes and /actuator/health answers slowly; a 1s timeout got the pod killed.
livenessProbe:
httpGet:
port: 8080
path: /actuator/health
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 6
readinessProbe:
httpGet:
port: 8080
path: /actuator/health
periodSeconds: 10
timeoutSeconds: 5
resources:
requests:
cpu: 100m
memory: 1Gi
limits:
memory: 3Gi # heap = 75%; 1.5Gi ran out of heap processing a large import
volumes:
- name: data
persistentVolumeClaim:
claimName: reitti-data
-27
View File
@@ -1,27 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: reitti
namespace: reitti
annotations:
cert-manager.io/cluster-issuer: letsencrypt
# No Authelia forward-auth middleware — Reitti authenticates against Authelia
# natively over OIDC. A middleware here would break the OIDC callback, the
# token-authenticated /api ingest endpoints (OwnTracks, GPSLogger, Overland)
# and magic share links.
spec:
tls:
- hosts:
- ${REITTI_HOST}
secretName: reitti-tls
rules:
- host: ${REITTI_HOST}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: reitti
port:
number: 8080
-4
View File
@@ -1,4 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: reitti
-133
View File
@@ -1,133 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: reitti
spec:
podSelector: {}
policyTypes:
- Ingress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-controller
namespace: reitti
spec:
podSelector:
matchLabels:
app: reitti
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-to-db
namespace: reitti
spec:
podSelector:
matchLabels:
app: reitti-db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: reitti
ports:
- port: 5432
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backup-to-db
namespace: reitti
spec:
podSelector:
matchLabels:
app: reitti-db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: reitti-backup
ports:
- port: 5432
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backup-egress
namespace: reitti
spec:
podSelector:
matchLabels:
app: reitti-backup
policyTypes:
- Egress
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
- ports:
- port: 8888
protocol: TCP
- ports:
- port: 443
protocol: TCP
- ports:
- port: 5432
protocol: TCP
to:
- podSelector:
matchLabels:
app: reitti-db
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-to-redis
namespace: reitti
spec:
podSelector:
matchLabels:
app: reitti-redis
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: reitti
ports:
- port: 6379
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-to-tile-cache
namespace: reitti
spec:
podSelector:
matchLabels:
app: reitti-tile-cache
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: reitti
ports:
- port: 80
-26
View File
@@ -1,26 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: reitti-data
namespace: reitti
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-synology-ssd
resources:
requests:
storage: 10Gi
---
# Map tile cache — recreatable, not backed up. nginx caps it at 2g tiles + 1g Panoramax.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: reitti-tile-cache
namespace: reitti
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-synology-ssd
resources:
requests:
storage: 5Gi
-29
View File
@@ -1,29 +0,0 @@
{
"kubernetes": {
"fileMatch": ["kubernetes/app/reitti/.+\\.yaml$"]
},
"packageRules": [
{
"matchFileNames": ["kubernetes/app/reitti/**"],
"semanticCommitScope": "k8s/reitti"
},
{
"matchFileNames": ["kubernetes/app/reitti/**"],
"matchPackageNames": ["dedicatedcode/reitti", "dedicatedcode/reitti-tile-cache"],
"matchUpdateTypes": ["patch", "minor"],
"automerge": true
},
{
"matchFileNames": ["kubernetes/app/reitti/**"],
"matchPackageNames": ["dedicatedcode/reitti", "dedicatedcode/reitti-tile-cache"],
"matchUpdateTypes": ["major"],
"automerge": false
},
{
"description": "Ignore infrastructure images",
"matchFileNames": ["kubernetes/app/reitti/**"],
"matchPackageNames": ["postgis/postgis", "redis", "creativeprojects/resticprofile"],
"enabled": false
}
]
}
@@ -1,26 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: reitti-backup-config
namespace: reitti
stringData:
profiles.yaml: ENC[AES256_GCM,data:aVuPPechcaGmXT0g6OTnISgGR2ZdBJvqrf6mpDJyIERXZiQC8aVq1RtkUeyVMs7Hed8OwuRfuo5xlG5206Bg8ynbBFEWsl+sbWRWOa9g+qSnO84Fhej+fbHITzC2BPk1q85CWJUpVcdHq1vgyKYluJpuYpS3HzrinsjTFpiziC7ft/lFjzebdlkFZgvq6cPFzYqP/8f54GOkYaR/cNr6ux6QLsbA3rfPOAfsMiaZFt3JfbTRNfqcM4eZw04N3bf4CVpyPjR69HZvlzHw0Gje+GX3vdez8bByUxo40aB9Aisvr/HeTM8L5njQDefN/zH1VGTSV2LfNk81soSowtxJ3RZ2hZYnx4dz0XUggvGqR5dhlGvT3pDK0v9lkRM1ahZw1x5q2zd3K7IcQLwYSckRdwC0j9vc8TUkHhyg+9x5TRrGy9hA4rCJtsGzTU/Sc4dcobueFXBGrIg9raTDknEo1D4Vq7H74Ce9RnemYlb1KJsjrtyqrpKkzIAChL1b6xhgOzg5YJ2UH6+laEsbC891OZp2PEdQY1lA8n36HXflsZnIQY8SOhToR6FoH3qzOB79a2I5jmJHI9O7S0L6NO2+fFDRgMbUNeIa9yJacN297Qui3paGQTcsGvSGQ7eAEH06VZXU/DX7TU0XiLfejIohm78QSmO7ZcTBxlQ1OTHc1Kiny1e0SomY7kxs1OL4SSBJirmymojuxogOGWblxt2AOz37eCFgp8L3sRPSHWGM982na6Ko7zUw1/bhukGoN445DsiuV59ilXSA0W5ci/PfrqzFOqZWKKDZfE89nCf+2P1thS3DmOpJnlG8tq5rde9QAqT0mgcvxo5Re+Bf/Ehavo0t79Gy35c6EEwPK8lEFXlSib84mfRiMnKBV60cQ4HS3xy78xLKPvjBpM4s8vbnMY4GJxCNAzOivhAfHAU3vTp/ZP8B0LJp7bNk7tre/gR+Q1DuqhwyCjo8sUZi4Cua3ILiKvcvU8ZXvjz+LfIymDocIxeFtRGHA2KceURa25v0hWrEI0Qzaz1m5XeYg76HhjcCU5WqT8CuFZNDlf+35uyKxhOZqr7kT2J/nZ/VYF2+sz9oBmeH/VW3OdgIc203e8wQIPBTd8OYpkabnwxDMlyiaG8MySZORS7kyD88Sy8bFJUN9IO7svav0WxZhJn4atAc2iqH81Y1s4WE1i87UqUDtwd5nOKXUFf8Fr6jXpB8G95hJCzgLFtrmX/6eg==,iv:Kp9nml6af8RmrVIIvAv8m647mMm5oe02T9TqkyIVY+U=,tag:WYbdlHbstN6XhcIP53VpqQ==,type:str]
restic-password-nas: ENC[AES256_GCM,data:FSRmDhSQHfHXomxPhefQ3WJNPVzSCNw/ML/mCiloViEkpVj92vcQbA==,iv:ijS0gKwp4dc/Oq346a/KLFnDBkPfhPzr4IUHbziGPxs=,tag:gE2wAuk+zWUJHgPlYQvwjw==,type:str]
restic-password-b2: ENC[AES256_GCM,data:4f0xRAKnWLsOFvu0GVu2FK7w8QS/w21AkCjSho7C1q8CV4aJSovvVA==,iv:WOru20OWYoN9jtW2iUdXpfuLd2SWiBXQ6Ncp5FUsRcE=,tag:vYa+obqI7gBHk9wY+tkIwg==,type:str]
B2_ACCOUNT_ID: ENC[AES256_GCM,data:52us2nMzoQ7p+I/+9+mJa+DK+MT8CdBDsg==,iv:E/ifDPwDyRJXOZBTPPwpLwCZzQ0n9IN+cdO/3O3u2e4=,tag:dFH0C7bZi4EcevoMJamzuQ==,type:str]
B2_ACCOUNT_KEY: ENC[AES256_GCM,data:jYDWYUj42GEtubZ5+RmYc+FT2FbJwg1PrzgtCb8I7Q==,iv:ZVvWw2aBv0iPAFzCn3L3MC3pwR/ru4zTDx0KsTiSQD8=,tag:PXLsKsT9ccSrZwUUONWnpQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCMDliMG1iNTVrNUZ2a0li
Tkc2WXFLbGhlbFYwdkovcjNZYXJBa0V1MFc0CnVEaEc1bzBCK0czSHh4dGE5Ky9Y
NjFWWGlScGdpODU3KzNmQzUzS3FkeVEKLS0tIDRXbHpST0RySVB1UEVRbWVYYytV
SzV4Q01MaGJGNmxqMm50OWh3S1RCbkEKaKPeVOU9Gvg+7RImg0BSLyl8DUNzCJDm
9gQd9z8IwciZE4St53kYSbQNCKMjz4yUc4mrbW04IXs5cTbnCLBspA==
-----END AGE ENCRYPTED FILE-----
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
encrypted_regex: ^(data|stringData|email)$
lastmodified: "2026-10-03T20:31:00Z"
mac: ENC[AES256_GCM,data:Jg964qmIW9hSp4N+4stwmE24qi4sNQfUA0YM5rH1QHWbeZS1gAXszgQQPPrOw+hStgNWZbsgiMJVIvF3v13qgMh6ZVSAFMmf3fWJ+tN6Dhrj79Qx+klaI8qXpXQsLvHX0gJFYBAyPvtBPoDRnHK8X/twAKm03QtCLCMHv3LnQ6Y=,iv:2De8vyYSIMKTWUXB0k5VAojeTFXuCwiuduXeGcCMHmA=,tag:eZzK4MPeCJItfYbbwQXJZQ==,type:str]
version: 3.13.3
-25
View File
@@ -1,25 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: reitti-credentials
namespace: reitti
stringData:
DB_USERNAME: ENC[AES256_GCM,data:s5+3cPVq,iv:xgQHj/ORXzDDsOoZZruGQrGTU+y+BRwkWC7Tk3CSAuI=,tag:6p6OdIL4CR0UDiiKOVsttA==,type:str]
DB_PASSWORD: ENC[AES256_GCM,data:GoWO3wMx2R7BAgkfb/GAk6vd7wIrbL8uqaCWf2TMwpgCr8yCY0mifw==,iv:KTkH59Woh/QBkx5lHWv/iV9LqrA1Q1NcpwtDkUKJAaY=,tag:HpHvG8kW2+RTDS0L1DjJQQ==,type:str]
DB_DATABASE_NAME: ENC[AES256_GCM,data:/Xrjy1quYwI=,iv:whj1qsDAKMqCeW8Ge+M0cZEjiSpYZizlXfBy3bhIbbg=,tag:8WrJv7bgFbbxIrz3uCZumA==,type:str]
OIDC_CLIENT_SECRET: ENC[AES256_GCM,data:WHk4EOUrYj7PnJiahEAy6yL7X155bj3s4wn7nzbeS8YHR5OOCIHa1b/atf1S7bktStkllIOg+EhmzGoHYFUgNg==,iv:zCsaEmx+9kvXGw8Lda+Qi7kIRl1kU7nWk9flFJzeZyA=,tag:eGD1noK0YBjVsIn23vnixQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBseDh0cGhIZkU0WHNJdThj
K1dWS29TSUhPWEFxdi9EOG1aZmlKcVJTTWxVCkM3RWtTOWl5Y0psU3BDNmFQSnFT
aGlURkFzOVVNd3FWclBYbEpIRXJ1QjQKLS0tIHQrRS9hRVVIYVBIazJFNGxhNWJm
dFFocWFxVkJIOVc5aUppQ2p3R2pNU28Kj2q+bIxGc14s8qs3Uc0/Dc9tymLMsT2o
x7dDpozVupQY/Pqo4RqWp6/OIOjVSTtqKV8A99KTyp9HBd2m9xjyWA==
-----END AGE ENCRYPTED FILE-----
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
encrypted_regex: ^(data|stringData|email)$
lastmodified: "2026-10-03T20:19:54Z"
mac: ENC[AES256_GCM,data:lE6AHBDRhNiTXlQMNLIMqBEDpYWfYg8TI6Mpd2as4Q+O7WckTuDkrOrULA063OgjJzohld5x3yExnR2weDMaiz2jXn0kDoXYrYxIYL4J4Ht98t8yndhtDMzSaVyJVyfRN3JRxfpJfVBTcD/mrpvo5fmQRJv0k/l0F4/lZY/UYSk=,iv:WUQv2PyrHt3tdUKsyhzggQ/kYosXebehmeNDqZQ4Lac=,tag:ooVml9rbNwtYaZGYPFv30w==,type:str]
version: 3.13.3
-12
View File
@@ -1,12 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: reitti-db
namespace: reitti
spec:
clusterIP: None
selector:
app: reitti-db
ports:
- port: 5432
targetPort: 5432
-38
View File
@@ -1,38 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: reitti
namespace: reitti
spec:
selector:
app: reitti
ports:
- port: 8080
targetPort: 8080
name: http
---
apiVersion: v1
kind: Service
metadata:
name: reitti-redis
namespace: reitti
spec:
selector:
app: reitti-redis
ports:
- port: 6379
targetPort: 6379
name: redis
---
apiVersion: v1
kind: Service
metadata:
name: reitti-tile-cache
namespace: reitti
spec:
selector:
app: reitti-tile-cache
ports:
- port: 80
targetPort: 80
name: http
-82
View File
@@ -1,82 +0,0 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: reitti-db
namespace: reitti
labels:
app: reitti-db
spec:
serviceName: reitti-db
replicas: 1
selector:
matchLabels:
app: reitti-db
template:
metadata:
labels:
app: reitti-db
spec:
securityContext:
runAsUser: 999
runAsGroup: 999
fsGroup: 999
containers:
- name: postgres
# Reitti requires PostGIS; the Debian variant keeps the postgres user at UID 999
# (the alpine variant uses 70). The image creates the postgis extension in POSTGRES_DB.
image: postgis/postgis:17-3.5
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_USERNAME
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_PASSWORD
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: reitti-credentials
key: DB_DATABASE_NAME
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
startupProbe:
tcpSocket:
port: 5432
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 30
livenessProbe:
tcpSocket:
port: 5432
periodSeconds: 30
failureThreshold: 5
readinessProbe:
tcpSocket:
port: 5432
periodSeconds: 10
failureThreshold: 3
resources:
requests:
cpu: 50m
memory: 256Mi
limits:
memory: 1Gi
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: nfs-synology-ssd
resources:
requests:
storage: 5Gi
+1 -1
View File
@@ -27,7 +27,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: vikunja - name: vikunja
image: vikunja/vikunja:2.7.0 image: vikunja/vikunja:2.6.0
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- containerPort: 3456 - containerPort: 3456
+2 -3
View File
@@ -38,7 +38,6 @@ stringData:
BLOG_HOST: ENC[AES256_GCM,data:eADRFTla/PPFLVCoP9uKvPZ1YhY=,iv://xbCGLkZ6guGMDU0MnVtGR0adgMqNbe0zrCerj7w8k=,tag:HHXvN6y3YvJ4U4TkENkYVA==,type:str] BLOG_HOST: ENC[AES256_GCM,data:eADRFTla/PPFLVCoP9uKvPZ1YhY=,iv://xbCGLkZ6guGMDU0MnVtGR0adgMqNbe0zrCerj7w8k=,tag:HHXvN6y3YvJ4U4TkENkYVA==,type:str]
VIKUNJA_HOST: ENC[AES256_GCM,data:1VVkvVrdx02jPxHsQoQI9zJKN9v/9mE=,iv:ZagDcljNclEGvmMzS6pJWTv+FMa/a/X6POaWb+kHJuo=,tag:RuaUoX8O4LrEs491Sp4UyQ==,type:str] VIKUNJA_HOST: ENC[AES256_GCM,data:1VVkvVrdx02jPxHsQoQI9zJKN9v/9mE=,iv:ZagDcljNclEGvmMzS6pJWTv+FMa/a/X6POaWb+kHJuo=,tag:RuaUoX8O4LrEs491Sp4UyQ==,type:str]
BACKUP_LOCAL_HOST: ENC[AES256_GCM,data:ABaTI3NKkhF7K2FpPwvvrHA0l/tCxAi4Qek=,iv:34ixxSpKU1c12uoMdk4nz2Vo/+5A/npB7NWMsWFytIM=,tag:qjw2fQBebCKnqCnAPiBHaw==,type:str] BACKUP_LOCAL_HOST: ENC[AES256_GCM,data:ABaTI3NKkhF7K2FpPwvvrHA0l/tCxAi4Qek=,iv:34ixxSpKU1c12uoMdk4nz2Vo/+5A/npB7NWMsWFytIM=,tag:qjw2fQBebCKnqCnAPiBHaw==,type:str]
REITTI_HOST: ENC[AES256_GCM,data:Zx0T6aUL/v6ogX1miRxzDmDQ31EImg==,iv:0LBRaaG1FHBXFWrtDX8Z6Cs75BEA7hNYm5FFrBHhyYk=,tag:Tup6HoL6E+L9GJKmv3x17Q==,type:str]
sops: sops:
age: age:
- enc: | - enc: |
@@ -51,6 +50,6 @@ sops:
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc
encrypted_regex: ^(data|stringData|email)$ encrypted_regex: ^(data|stringData|email)$
lastmodified: "2026-10-03T20:20:00Z" lastmodified: "2026-09-07T11:47:37Z"
mac: ENC[AES256_GCM,data:xN+k2RvU+IJyYzLRIExm0qM5F/K4s19jm0Sp1fo4L3V2dZHSb1J/JtdtxpbalA3qGxy82qDosagrhrNtdsL2/Ht7JO5f1T3Q1Z5smOBOkvWrjPqnyOWGGwe4j77UY41k50kXNh1VFbhjBYkEei+8191BlMkEmTNSdBvFdvzydIw=,iv:1Q3otFunhnMgrJI8z4XFsp92PHmogEvYi99qAkgJomo=,tag:ikTXnDjTG9fNFrumBGW5Lw==,type:str] mac: ENC[AES256_GCM,data:4ocnThiPrXCqKTKKgwaincewzI99O7cl9CGnJHrwLRFm8vA2G6MA8yGvywoKjmln8mEfPTTcMMZY8Nd7wFKHz9i4m+CHvzC7kPhTVIDW2HrkFoN7RgywPcgnP+mrco4wOd/huBLdv9+v/j4Iz5lXBMZgbVVkNdWV4xZ4Zx3gtyM=,iv:bfK9KN4E5nZYm6CwaFm3sxG62nDnNiuP5xsIreRHkAc=,tag:wi9r3EcJOHX0azzNVpGw0Q==,type:str]
version: 3.13.3 version: 3.13.3
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -12,8 +12,7 @@
"local>oleksandr/homelab//kubernetes/app/paperless/renovate.json", "local>oleksandr/homelab//kubernetes/app/paperless/renovate.json",
"local>oleksandr/homelab//kubernetes/app/lubelogger/renovate.json", "local>oleksandr/homelab//kubernetes/app/lubelogger/renovate.json",
"local>oleksandr/homelab//kubernetes/app/firefly/renovate.json", "local>oleksandr/homelab//kubernetes/app/firefly/renovate.json",
"local>oleksandr/homelab//kubernetes/app/podsync/renovate.json", "local>oleksandr/homelab//kubernetes/app/podsync/renovate.json"
"local>oleksandr/homelab//kubernetes/app/reitti/renovate.json"
], ],
"enabledManagers": ["kubernetes", "custom.regex"], "enabledManagers": ["kubernetes", "custom.regex"],
"automergeType": "branch", "automergeType": "branch",