Compare commits

..
Author SHA1 Message Date
hermes-bot 14dc5247b7 fix(youtrack): OIDC client as an OIDCClient resource, not Ingress annotations
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
Uses the OIDCClient CRD from #1535; the Ingress carries only routing and
DNS again. The Flux Kustomization treats OIDCClient as current on apply,
since its Ready reflects Authentik state (the group), as with KumaMonitor.
2026-11-01 09:31:45 +00:00
hermes-bot 68d1a174db fix(youtrack): OIDC client from authentik-gate-sync, no blueprint
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
The provider, application and group policy are now created by
authentik-gate-sync from the Ingress annotations auth.renner.uno/oidc-client
and auth.renner.uno/group (#1535); the youtrack.yaml blueprint is gone.
The group YouTrack Users stays managed in Authentik.
2026-11-01 09:22:40 +00:00
hermes-bot 7efc62e216 fix(youtrack): take the YouTrack Users group out of the blueprint
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was canceled
Groups are managed in Authentik itself. The blueprint now only binds the
application to the group by name (!Find).

The YouTrack entries move to their own blueprint (youtrack.yaml). Authentik
imports a blueprint atomically (importer.py apply() runs _apply_models in
one transaction), so while the group does not exist the whole YouTrack
blueprint rolls back: no provider, no application, login closed. In the
shared OAuth2 blueprint the same miss would also have blocked every other
provider.
2026-11-01 09:16:22 +00:00
hermes-bot f50b33cadf fix(youtrack): manage YouTrack Users members in Authentik, not the blueprint
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline failed
Same as Wiki Readers: the blueprint only ensures the group exists, because
the application's policy binding refers to it; membership is edited in
Authentik.
2026-11-01 08:45:40 +00:00
hermes-bot f96737c576 feat(youtrack): YouTrack Server, LAN only, login through Authentik
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was canceled
Namespace youtrack: jetbrains/youtrack 2026.2.19728 (digest-pinned), one
replica with Recreate, PVC youtrack (data/conf/logs/backups as subPaths),
Velero youtrack-daily plus restore-youtrack like the other apps.

The Ingress carries only dns.renner.uno/internal, so the UDM gets a record
and netbird-service-sync publishes nothing: the host is not reachable from
the internet until login goes through Authentik and a later PR adds the
public label.

Authentik blueprint: group YouTrack Users, confidential OIDC provider
(client_id youtrack; YouTrack's OpenID Connect auth module requires a
client secret), application slug youtrack, bound to the group.

YouTrack Server has no documented unattended first install (2026.2 docs:
the Configuration Wizard is mandatory, the skip flag exists for upgrades
only), so the wizard and the auth module are a one-time owner step,
accepted by the owner.
2026-11-01 08:42:43 +00:00
k.renner 53d7e716f8 Merge pull request 'fix(loki): enforce retention via the compactor, keep 365 days' (#1532) from worktree-loki-retention-365d into main
ci/woodpecker/cron/security-scan Pipeline was successful
ci/woodpecker/cron/ci-claude-refresh Pipeline was successful
ci/woodpecker/cron/e2e Pipeline failed
Reviewed-on: #1532
2026-10-31 06:10:42 +00:00
security-bot 61e4ee2ba8 chore(image-automation): bump ghcr.io/paperless-ngx/paperless-ngx:3.4.1
Updates managed by image-automation-controller.
2026-10-31 05:50:56 +00:00
security-bot b447c57e78 chore(image-automation): bump ghcr.io/linuxserver/lidarr:3.1.6.5079-ls46
Updates managed by image-automation-controller.
2026-10-31 00:23:17 +00:00
security-bot 4f3cf541a4 chore(image-automation): bump docker.gitea.com/gitea-mcp-server:1.12.0
Updates managed by image-automation-controller.
2026-10-30 19:30:16 +00:00
security-bot 6463c38f68 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-1343
Updates managed by image-automation-controller.
2026-10-30 13:51:12 +00:00
security-bot b86aaf3f88 chore(image-automation): bump ghcr.io/music-assistant/server:2.10.9
Updates managed by image-automation-controller.
2026-10-30 13:50:57 +00:00
claude-botandClaude Opus 5.5 c9944cfce8 fix(loki): enforce retention via the compactor, keep 365 days
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
limits_config.retention_period was set (2160h) but never enforced: the
live config has no compactor block, so retention_enabled is false and
Loki keeps everything (logs from 2026-05-15 are still queryable).

Enable compactor retention (working_directory under the existing
/var/loki PVC, delete_request_store filesystem) and raise the period to
365 days.

Sizing: storage-loki-0 holds 21.3 GiB of 80 GiB after 5.5 months
(~0.13 GiB/day average, ~0.23 GiB/day over 22.-25.10). 365 days at the
recent rate is ~84 GiB, so the PVC may need expanding later
(ceph-block allows volume expansion).

Rendered with chart loki 7.5.0 and checked with
`loki:3.6.11 -verify-config`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:38:29 +01:00
k.renner 717d1ad619 Merge pull request 'fix(paperless): drop the off-site monitor of the internal Syncthing UI' (#1531) from paperless-drop-syncthing-monitor into main
Reviewed-on: #1531
2026-10-30 13:32:02 +00:00
claude-botandClaude Opus 5.5 40f30412aa fix(paperless): drop the off-site monitor of the internal Syncthing UI
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
syncthing.paperless.renner.uno is internal only (no public labels, no public
DNS record), so Uptime Kuma on the VPS cannot reach it and kept the Documents
group down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:29:42 +01:00
security-bot 3f73e7cd3a chore(image-automation): bump gitea.renner.uno/gitea_admin/kuma-sync:2026-10-30-1314
Updates managed by image-automation-controller.
2026-10-30 13:23:56 +00:00
k.renner a7543cb78b Merge pull request 'feat(alloy-syslog): label UniFi plain syslog on udp-5514 separately from CEF' (#1530) from worktree-alloy-unifi-syslog-label into main
Reviewed-on: #1530
2026-10-30 13:23:48 +00:00
claude-botandClaude Opus 5.5 229e0cf5d8 feat(alloy-syslog): label UniFi plain syslog on udp-5514 separately from CEF
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
UniFi activity logging has a single target, so the UDM SIEM CEF events,
the UDM system log (log_all_contents) and the AP/switch device logs
(debug) all arrive on udp-5514. Split them in loki.process.udm_cef:

- CEF lines keep source="udm-siem" and the existing CEF labels.
- Everything else gets source="unifi-syslog" plus host and app parsed
  from the line header (UDM: "<host> <host> <app>[pid]:", devices:
  "<host> <mac>,<model>-<fw>: [: ]<app>[pid]:").

The listener no longer sets source statically; each stage.match sets it,
so no label is overwritten. Regex checked against 10 min of live lines
(all non-CEF lines match); config validated with alloy v1.21.3
`validate --stability.level=experimental`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:22:28 +01:00
security-bot b7cf7632c6 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-1257
Updates managed by image-automation-controller.
2026-10-30 13:21:12 +00:00
k.renner b77b0a4d0d Merge pull request 'feat(kuma-sync): one mail per outage via a root group' (#1525) from kuma-root-group into main
ci/woodpecker/push/build-ci-images Pipeline was successful
Reviewed-on: #1525
Reviewed-by: Review Bot <review-bot@renner.uno>
2026-10-30 13:14:40 +00:00
security-bot 2485b3ad38 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-1158
Updates managed by image-automation-controller.
2026-10-30 12:24:28 +00:00
k.renner a49c852666 Merge pull request 'feat(paperless): Syncthing UI behind the Authentik gate' (#1529) from worktree-syncthing-ui-gate into main
ci/woodpecker/cron/e2e Pipeline failed
ci/woodpecker/cron/security-scan Pipeline was successful
Reviewed-on: #1529
2026-10-30 10:45:08 +00:00
claude-botandClaude Opus 5.5 3aa2cf7616 feat(paperless): Syncthing UI behind the Authentik gate
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
Serve the UI at syncthing.paperless.renner.uno for Paperless Admins. That hostname was the sync LoadBalancer's DNS name, so the LoadBalancer moves to sync.paperless.renner.uno and the DNS probe follows it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:40:45 +01:00
security-bot 0a36c324da chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-0913
Updates managed by image-automation-controller.
2026-10-30 09:24:27 +00:00
security-bot 8d3578f020 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-0728
Updates managed by image-automation-controller.
2026-10-30 07:54:27 +00:00
security-bot 10f1a88802 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-0719
Updates managed by image-automation-controller.
2026-10-30 07:24:27 +00:00
security-bot 4dd46a8e7b chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-30-0624
Updates managed by image-automation-controller.
2026-10-30 06:54:27 +00:00
security-bot 859d1a7c65 chore(image-automation): bump lscr.io/linuxserver/lidarr:3.1.6.5079-ls46
Updates managed by image-automation-controller.
2026-10-30 06:50:46 +00:00
k.renner 0575a50d9e Merge pull request 'fix(lidarr): scan ghcr.io directly instead of lscr.io redirector' (#1528) from alert-fix/issue-1527 into main
Reviewed-on: #1528
2026-10-30 06:22:12 +00:00
security-bot 33b7b58849 chore(image-automation): bump ghcr.io/paperless-ngx/paperless-ngx:3.4.0
Updates managed by image-automation-controller.
2026-10-29 22:50:43 +00:00
hermes-bot dab7c10eca fix(lidarr): scan ghcr.io directly instead of lscr.io
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
lscr.io 302-redirects the tag-list request to ghcr.io and the
image-reflector's follow-up arrives unauthenticated (UNAUTHORIZED),
leaving ImageRepository/lidarr not Ready since 2026-10-29T18:56Z.
ghcr.io/linuxserver/lidarr is the same repository (identical digest
for 3.1.6.5079-ls46) and scans anonymously. Workload refs follow so
the imagepolicy setter keeps matching.

Closes #1527
2026-10-29 21:24:11 +00:00
security-bot 378f7e3429 chore(image-automation): bump woodpeckerci/woodpecker-agent:v3.20.1
Updates managed by image-automation-controller.
2026-10-29 20:54:22 +00:00
security-bot fdc08827fb chore(image-automation): bump woodpeckerci/woodpecker-server:v3.20.1
Updates managed by image-automation-controller.
2026-10-29 19:54:51 +00:00
security-bot 3d504c2f62 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-29-1803
Updates managed by image-automation-controller.
2026-10-29 18:24:26 +00:00
k.renner d56deb096e Merge pull request 'feat(shelly-manager): roll firmware out to battery devices' (#1526) from shelly-manager-sleepy-rollout into main
Reviewed-on: #1526
2026-10-29 17:57:37 +00:00
claude-botandClaude Opus 5.5 222965ba47 feat(shelly-manager): roll firmware out to battery devices
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
Firmware:SleepyRollout makes shelly-manager push a battery device's update
when it calls in; it was unset, so the rollout never took them along.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185Qb5YG28FfnVi1ujMEV5C
2026-10-29 18:54:23 +01:00
security-bot 394bf91c37 chore(image-automation): bump gitea.renner.uno/konairius/mqtt-account-controller:2026-10-29-1634
Updates managed by image-automation-controller.
2026-10-29 16:34:44 +00:00
security-bot 2f7bc33b84 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-29-1545
Updates managed by image-automation-controller.
2026-10-29 15:54:25 +00:00
security-bot 6c045e2e56 chore(image-automation): bump gitea.renner.uno/konairius/shelly-manager:2026-10-29-1524
Updates managed by image-automation-controller.
2026-10-29 15:35:31 +00:00
30 changed files with 470 additions and 51 deletions
@@ -103,6 +103,16 @@ data:
slug: paperless-proxy
state: absent
# syncthing.paperless.renner.uno is gated by authentik-gate-sync
# (kubernetes/apps/paperless/syncthing.yaml), which admits this group.
# Members are managed in Authentik.
- model: authentik_core.group
identifiers:
name: Paperless Admins
state: present
attrs:
is_superuser: false
# vscode.home.renner.uno is gated by authentik-gate-sync
# (kubernetes/apps/home-assistant/vscode-ingress.yaml), which admits this
# group. Members are managed in Authentik.
+1 -1
View File
@@ -23,7 +23,7 @@ spec:
type: RuntimeDefault
containers:
- name: gitea-mcp
image: docker.gitea.com/gitea-mcp-server:1.11.0 # {"$imagepolicy": "flux-system:gitea-mcp"}
image: docker.gitea.com/gitea-mcp-server:1.12.0 # {"$imagepolicy": "flux-system:gitea-mcp"}
# Image has no ENTRYPOINT (binary is in CMD), so args alone would replace it.
command:
- /app/gitea-mcp
@@ -64,7 +64,7 @@ spec:
type: RuntimeDefault
containers:
- name: shelly-manager
image: gitea.renner.uno/konairius/shelly-manager:2026-10-29-0949 # {"$imagepolicy": "flux-system:shelly-manager"}
image: gitea.renner.uno/konairius/shelly-manager:2026-10-30-1343 # {"$imagepolicy": "flux-system:shelly-manager"}
imagePullPolicy: IfNotPresent
ports:
- name: http
@@ -106,6 +106,9 @@ spec:
# The URL devices download firmware from: Service shelly-manager-firmware.
- name: Firmware__PublicBaseUrl
value: http://firmware.shelly-manager.renner.uno
# Battery devices get their update when they call in.
- name: Firmware__SleepyRollout
value: "true"
- name: ShellyManager__DnsSuffix
value: iot.renner.uno
# BLE radios: ESP32 esphome bluetooth_proxy nodes (e.g. the M5 Atom
@@ -223,7 +223,7 @@ spec:
type: RuntimeDefault
containers:
- name: controller
image: gitea.renner.uno/konairius/mqtt-account-controller:2026-10-28-0657 # {"$imagepolicy": "flux-system:mqtt-account-controller"}
image: gitea.renner.uno/konairius/mqtt-account-controller:2026-10-29-1634 # {"$imagepolicy": "flux-system:mqtt-account-controller"}
env:
- name: BROKER_URL
value: ssl://mosquitto.home-assistant.svc.cluster.local:8884
+1 -1
View File
@@ -30,7 +30,7 @@ spec:
type: RuntimeDefault
containers:
- name: controller
image: gitea.renner.uno/gitea_admin/kuma-sync:2026-10-29-1349 # {"$imagepolicy": "flux-system:kuma-sync"}
image: gitea.renner.uno/gitea_admin/kuma-sync:2026-10-30-1314 # {"$imagepolicy": "flux-system:kuma-sync"}
env:
- name: KUMA_URL
value: https://kuma.renner.uno
@@ -142,4 +142,4 @@ spec:
- "[fd02:47::1]:53"
- "10.2.47.1:53"
labels:
dns_name: syncthing.paperless.renner.uno
dns_name: sync.paperless.renner.uno
@@ -158,43 +158,69 @@ spec:
relabel_rules = loki.relabel.syslog.rules
}
// UniFi UDM SIEM Server (Network app) — UDP/5514. UDM emits CEF
// (Common Event Format), not RFC syslog: payload starts with
// "<bsd-ts> <iso-ts> <device-name> CEF:0|Vendor|Product|...".
// raw listener captures verbatim; loki.process.udm_cef extracts
// CEF header + UNIFI* extension fields and promotes a curated
// low-cardinality set to labels.
// UniFi activity logging — UDP/5514, one target for two payloads:
// the UDM SIEM events in CEF ("<bsd-ts> <device-name> CEF:0|...")
// and plain syslog from the UDM (log_all_contents) and from every
// adopted AP/switch (debug). raw listener captures verbatim;
// loki.process.udm_cef sets `source` per payload type.
loki.source.syslog "udp_5514" {
listener {
address = "0.0.0.0:5514"
protocol = "udp"
syslog_format = "raw"
labels = { job = "syslog", listener = "udp-5514", source = "udm-siem" }
labels = { job = "syslog", listener = "udp-5514" }
}
forward_to = [loki.process.udm_cef.receiver]
}
// CEF parser for UDM SIEM payload. The listener also receives the
// UDM's plain syslog (log_all_contents), which does not match and
// passes through unlabelled. CEF extension keys differ per event
// type, so the regex anchors only on the header
// (vendor|product|product_version|sig_id|name|sev), UNIFIcategory,
// UNIFIhost and the trailing msg. The full raw line stays the log
// content.
loki.process "udm_cef" {
forward_to = [loki.write.default.receiver]
stage.regex {
expression = "CEF:\\d+\\|(?P<vendor>[^|]*)\\|(?P<product>[^|]*)\\|(?P<product_version>[^|]*)\\|(?P<signature_id>[^|]*)\\|(?P<event_name>[^|]*)\\|(?P<cef_severity>[^|]*)\\|UNIFIcategory=(?P<category>.+?) UNIFIhost=(?P<unifi_host>.+?) \\S+=.* msg=(?P<msg>.+)$"
// CEF: extension keys differ per event type, so the regex
// anchors only on the header
// (vendor|product|product_version|sig_id|name|sev),
// UNIFIcategory, UNIFIhost and the trailing msg. The full raw
// line stays the log content.
stage.match {
selector = "{listener=\"udp-5514\"} |= \"CEF:\""
stage.static_labels {
values = { source = "udm-siem" }
}
stage.regex {
expression = "CEF:\\d+\\|(?P<vendor>[^|]*)\\|(?P<product>[^|]*)\\|(?P<product_version>[^|]*)\\|(?P<signature_id>[^|]*)\\|(?P<event_name>[^|]*)\\|(?P<cef_severity>[^|]*)\\|UNIFIcategory=(?P<category>.+?) UNIFIhost=(?P<unifi_host>.+?) \\S+=.* msg=(?P<msg>.+)$"
}
stage.labels {
values = {
vendor = "vendor",
product = "product",
signature_id = "signature_id",
event_name = "event_name",
category = "category",
}
}
}
stage.labels {
values = {
vendor = "vendor",
product = "product",
signature_id = "signature_id",
event_name = "event_name",
category = "category",
// Plain syslog. UDM: "<ts> <host> <host> <app>[pid]: ...";
// AP/switch: "<ts> <host> <mac>,<model>-<fw>: [: ]<app>[pid]: ...".
stage.match {
selector = "{listener=\"udp-5514\"} != \"CEF:\""
stage.static_labels {
values = { source = "unifi-syslog" }
}
stage.regex {
expression = "^\\S+ +\\d+ \\S+ (?P<host>\\S+) (?:[0-9a-f]{12},\\S+:(?: :)? |\\S+ )(?P<app>[A-Za-z0-9_./+-]+)"
}
stage.labels {
values = {
host = "host",
app = "app",
}
}
}
}
@@ -136,7 +136,7 @@ spec:
prober: dns
timeout: 5s
dns:
query_name: syncthing.paperless.renner.uno
query_name: sync.paperless.renner.uno
query_type: A
valid_rcodes: [NOERROR]
validate_answer_rrs:
@@ -39,8 +39,14 @@ spec:
replication_factor: 1
storage:
type: filesystem
# retention_period is only enforced by the compactor with
# retention_enabled; Loki keeps logs forever otherwise.
compactor:
working_directory: /var/loki/compactor
retention_enabled: true
delete_request_store: filesystem
limits_config:
retention_period: 2160h
retention_period: 8760h
ingestion_rate_mb: 10
ingestion_burst_size_mb: 20
max_streams_per_user: 10000
@@ -54,7 +54,7 @@ spec:
# stdlib only; Flux keeps the tag in lockstep via the shared image
# policy) — no extra dependency.
- name: reconcile-publish-ip
image: ghcr.io/music-assistant/server:2.10.8 # {"$imagepolicy": "flux-system:music-assistant"}
image: ghcr.io/music-assistant/server:2.10.9 # {"$imagepolicy": "flux-system:music-assistant"}
command: ["/app/venv/bin/python", "/scripts/reconcile.py"]
volumeMounts:
- name: data
@@ -67,7 +67,7 @@ spec:
# the stock file is the one it was written against (2.10.7 = 2.10.8);
# any other version keeps the stock provider.
- name: pocketcasts-overlay
image: ghcr.io/music-assistant/server:2.10.8 # {"$imagepolicy": "flux-system:music-assistant"}
image: ghcr.io/music-assistant/server:2.10.9 # {"$imagepolicy": "flux-system:music-assistant"}
command:
- /bin/sh
- -euc
@@ -88,7 +88,7 @@ spec:
readOnly: true
containers:
- name: music-assistant
image: ghcr.io/music-assistant/server:2.10.8 # {"$imagepolicy": "flux-system:music-assistant"}
image: ghcr.io/music-assistant/server:2.10.9 # {"$imagepolicy": "flux-system:music-assistant"}
env:
- name: LOG_LEVEL
value: info
+2 -2
View File
@@ -93,7 +93,7 @@ spec:
type: RuntimeDefault
containers:
- name: lidarr
image: lscr.io/linuxserver/lidarr:3.1.6.5079-ls46 # {"$imagepolicy": "flux-system:lidarr"}
image: ghcr.io/linuxserver/lidarr:3.1.6.5079-ls46 # {"$imagepolicy": "flux-system:lidarr"}
env:
- name: PUID
value: "1000"
@@ -140,7 +140,7 @@ spec:
drop: ["ALL"]
add: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETGID", "SETUID"]
- name: reconcile
image: lscr.io/linuxserver/lidarr:3.1.6.5079-ls46 # {"$imagepolicy": "flux-system:lidarr"}
image: ghcr.io/linuxserver/lidarr:3.1.6.5079-ls46 # {"$imagepolicy": "flux-system:lidarr"}
command: ["sh", "/scripts/reconcile.sh"]
volumeMounts:
- name: config
+1 -1
View File
@@ -182,7 +182,7 @@ spec:
drop: ["ALL"]
containers:
- name: paperless
image: ghcr.io/paperless-ngx/paperless-ngx:3.3.4 # {"$imagepolicy": "flux-system:paperless-ngx"}
image: ghcr.io/paperless-ngx/paperless-ngx:3.4.1 # {"$imagepolicy": "flux-system:paperless-ngx"}
ports:
- name: http
containerPort: 8000
+33 -10
View File
@@ -52,11 +52,8 @@ spec:
- name: syncthing
image: syncthing/syncthing:2.1.7@sha256:2b71da7c0d0a91a6ae5285ad079226fecc0a365d08b27720e1f7037b018f7546
env:
# UI bind: any-interface so the ClusterIP Service can reach
# it. Network exposure is gated by the absence of an Ingress
# and the namespace default-deny CNP — set a UI password in
# the Syncthing UI on first port-forward access before
# publishing it.
# UI bind: any-interface so the ClusterIP Service can reach it.
# External access goes through the syncthing-ui Ingress only.
- name: STGUIADDRESS
value: "0.0.0.0:8384"
- name: PUID
@@ -115,10 +112,6 @@ spec:
persistentVolumeClaim:
claimName: paperless-consume
---
# UI Service — ClusterIP only. Access via `kubectl -n paperless
# port-forward svc/syncthing-ui 8384:8384` for first-time setup
# (set admin password). Future Ingress + Authentik gate is a
# separate change once auth is configured.
apiVersion: v1
kind: Service
metadata:
@@ -132,6 +125,36 @@ spec:
port: 8384
targetPort: ui
---
# LAN-only UI: Paperless Admins through the Authentik gate.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: syncthing-ui
namespace: paperless
labels:
dns.renner.uno/internal: "true"
annotations:
traefik.ingress.kubernetes.io/router.middlewares: authentik-gate@kubernetescrd
cert-manager.io/cluster-issuer: letsencrypt-cluster
auth.renner.uno/group: Paperless Admins
spec:
ingressClassName: traefik
rules:
- host: syncthing.paperless.renner.uno
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: syncthing-ui
port:
number: 8384
tls:
- secretName: syncthing-ui-tls
hosts:
- syncthing.paperless.renner.uno
---
# Sync ports — LAN-reachable LoadBalancer. Peers (phones, laptops)
# connect here for the dropbox sync. external-dns publishes the
# hostname into UniFi DNS only (no cloudflare label); off-LAN peers
@@ -146,7 +169,7 @@ metadata:
dns.renner.uno/internal: "true"
annotations:
io.cilium/lb-ipam-ips: "10.2.99.85,fd99::85"
external-dns.kubernetes.io/hostname: syncthing.paperless.renner.uno
external-dns.kubernetes.io/hostname: sync.paperless.renner.uno
spec:
type: LoadBalancer
externalTrafficPolicy: Local
+1 -1
View File
@@ -34,7 +34,7 @@ spec:
# Image automation, range 3.x (see image-automation/woodpecker.yaml).
# MUST stay version-matched with woodpecker-server (gRPC parity) — both
# track the same range/filter so they bump together on each release.
image: woodpeckerci/woodpecker-agent:v3.20.0 # {"$imagepolicy": "flux-system:woodpecker-agent"}
image: woodpeckerci/woodpecker-agent:v3.20.1 # {"$imagepolicy": "flux-system:woodpecker-agent"}
env:
- name: WOODPECKER_SERVER
value: woodpecker.woodpecker.svc.cluster.local:9000 # in-cluster gRPC, replaces LXC :9000
+1 -1
View File
@@ -40,7 +40,7 @@ spec:
# minor + patch auto-update within 3.x; only the 4.0 major is held for
# a reviewed bump. Safe now the DB is postgres (the old sqlite-surprise
# -bump hazard is gone). Stays in lockstep with the agent.
image: woodpeckerci/woodpecker-server:v3.20.0 # {"$imagepolicy": "flux-system:woodpecker-server"}
image: woodpeckerci/woodpecker-server:v3.20.1 # {"$imagepolicy": "flux-system:woodpecker-server"}
env:
- name: WOODPECKER_HOST
value: https://ci.renner.uno
+90
View File
@@ -0,0 +1,90 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: youtrack
namespace: youtrack
labels:
app.kubernetes.io/name: youtrack
spec:
replicas: 1
# One process owns the database directory.
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: youtrack
template:
metadata:
labels:
app.kubernetes.io/name: youtrack
spec:
automountServiceAccountToken: false
enableServiceLinks: false
securityContext:
runAsNonRoot: true
# The image's service account.
runAsUser: 13001
runAsGroup: 13001
fsGroup: 13001
seccompProfile:
type: RuntimeDefault
containers:
- name: youtrack
image: jetbrains/youtrack:2026.2.19728@sha256:c5e9cedc6fb1d7bcc9b3b56fc3f63e563623e1cd39396161eb70957991583950
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
ports:
- name: http
containerPort: 8080
resources:
requests:
cpu: 250m
memory: 2Gi
limits:
memory: 4Gi
startupProbe:
tcpSocket:
port: http
periodSeconds: 10
failureThreshold: 60
readinessProbe:
tcpSocket:
port: http
periodSeconds: 10
livenessProbe:
tcpSocket:
port: http
periodSeconds: 30
failureThreshold: 4
volumeMounts:
- name: youtrack
mountPath: /opt/youtrack/data
subPath: data
- name: youtrack
mountPath: /opt/youtrack/conf
subPath: conf
- name: youtrack
mountPath: /opt/youtrack/logs
subPath: logs
- name: youtrack
mountPath: /opt/youtrack/backups
subPath: backups
volumes:
- name: youtrack
persistentVolumeClaim:
claimName: youtrack
---
apiVersion: v1
kind: Service
metadata:
name: youtrack
namespace: youtrack
spec:
selector:
app.kubernetes.io/name: youtrack
ports:
- name: http
port: 8080
targetPort: http
+27
View File
@@ -0,0 +1,27 @@
# LAN-only (UDM record via dns.renner.uno/internal); no public label until login goes through Authentik.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: youtrack
namespace: youtrack
labels:
dns.renner.uno/internal: "true"
annotations:
cert-manager.io/cluster-issuer: letsencrypt-cluster
spec:
ingressClassName: traefik
tls:
- hosts:
- youtrack.renner.uno
secretName: youtrack-tls
rules:
- host: youtrack.renner.uno
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: youtrack
port:
number: 8080
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pvc.yaml
- deployment.yaml
- ingress.yaml
- oidcclient.yaml
+13
View File
@@ -0,0 +1,13 @@
# Authentik OIDC client, created by authentik-gate-sync; issuer https://auth.renner.uno/application/o/youtrack/.
apiVersion: auth.renner.uno/v1alpha1
kind: OIDCClient
metadata:
name: youtrack
namespace: youtrack
spec:
launchURL: https://youtrack.renner.uno
group: YouTrack Users
redirectURIs:
# YouTrack generates the callback when the auth module is created; pin it strict once known.
- matchingMode: regex
url: ^https://youtrack\.renner\.uno/.*$
+17
View File
@@ -0,0 +1,17 @@
# YouTrack data, conf, logs and backups (subPaths); Velero youtrack-daily.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: youtrack
namespace: youtrack
labels:
app.kubernetes.io/name: youtrack
annotations:
kustomize.toolkit.fluxcd.io/prune: disabled
spec:
accessModes:
- ReadWriteOnce
storageClassName: ceph-block
resources:
requests:
storage: 20Gi
+28
View File
@@ -394,3 +394,31 @@ spec:
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: restore-youtrack
namespace: flux-system
spec:
interval: 10m
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/restore/youtrack
prune: true
wait: true
dependsOn:
- name: restore-gitea
- name: velero-backups-synced
- name: infrastructure-ceph-cluster
healthCheckExprs:
- apiVersion: velero.io/v1
kind: Restore
failed: >-
has(status.phase) && (status.phase in ['Failed', 'PartiallyFailed'] ||
(status.phase == 'FailedValidation' && !(has(status.validationErrors) &&
status.validationErrors.exists(e, e.startsWith('No backups found for schedule')))))
current: >-
has(status.phase) && (status.phase == 'Completed' || status.phase == 'FailedValidation')
+25
View File
@@ -0,0 +1,25 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: youtrack
namespace: flux-system
spec:
interval: 10m
retryInterval: 1m
timeout: 15m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/apps/youtrack
prune: true
wait: true
# OIDCClient Ready tracks Authentik (e.g. the group exists), not this apply.
healthCheckExprs:
- apiVersion: auth.renner.uno/v1alpha1
kind: OIDCClient
current: "true"
dependsOn:
- name: restore-youtrack
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
@@ -4,7 +4,7 @@ metadata:
name: lidarr
namespace: flux-system
spec:
image: lscr.io/linuxserver/lidarr
image: ghcr.io/linuxserver/lidarr
interval: 1h
---
# Tags are <maj>.<min>.<patch>.<build>-ls<n>. Two numbers move, and BOTH
@@ -83,6 +83,11 @@ metadata:
---
apiVersion: v1
kind: Namespace
metadata:
name: youtrack
---
apiVersion: v1
kind: Namespace
metadata:
name: immich
---
@@ -32,6 +32,7 @@ resources:
- wordpress-ns.yaml
- ai-ns.yaml
- navidrome-ns.yaml
- youtrack-ns.yaml
- uptime-monitor-ns.yaml
- kuma-sync-ns.yaml
- cloudflare-lb-sync-ns.yaml
@@ -145,8 +145,8 @@ spec:
# Allow Syncthing peer-to-peer sync from the LAN/world.
# - 22000 TCP+QUIC: actual sync traffic between peers.
# - 21027 UDP: local-discovery broadcast packets from peers on the LAN.
# UI (8384) is intentionally NOT listed — accessed via port-forward
# until an Ingress + Authentik gate is added.
# UI (8384) is intentionally NOT listed — authentik-gate-sync generates the
# CNP syncthing-ui-gate that admits traefik.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
@@ -0,0 +1,107 @@
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: default-deny-ingress
namespace: youtrack
spec:
endpointSelector: {}
ingress:
- fromEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": youtrack
- fromEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": ingress
app.kubernetes.io/name: traefik
- fromEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": monitoring
- fromEntities:
- host
- remote-node
# ICMP — all standard ICMPv4 + ICMPv6 from any cluster pod. See
# home-assistant-ns.yaml for the rationale (CT-RELATED path not
# passing related ICMP empirically; per-namespace shape, mirroring
# commit 3c517a0's verified-safe pattern with the 66dbe9f type set).
- fromEndpoints:
- matchExpressions:
- key: io.kubernetes.pod.namespace
operator: Exists
icmps:
- fields:
- { type: 0, family: IPv4 }
- { type: 3, family: IPv4 }
- { type: 8, family: IPv4 }
- { type: 11, family: IPv4 }
- { type: 12, family: IPv4 }
- { type: 1, family: IPv6 }
- { type: 2, family: IPv6 }
- { type: 3, family: IPv6 }
- { type: 4, family: IPv6 }
- { type: 128, family: IPv6 }
- { type: 129, family: IPv6 }
- { type: 133, family: IPv6 }
- { type: 134, family: IPv6 }
- { type: 135, family: IPv6 }
- { type: 136, family: IPv6 }
- { type: 143, family: IPv6 }
egress:
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": youtrack
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": ingress
app.kubernetes.io/name: traefik
- toEndpoints:
- matchLabels:
"k8s:io.kubernetes.pod.namespace": kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
# host/remote-node: kubelet probes + node-local reach (Ceph mons on host net)
- toEntities:
- host
- remote-node
# ICMP — egress mirror; see ingress block above.
- toEndpoints:
- matchExpressions:
- key: io.kubernetes.pod.namespace
operator: Exists
icmps:
- fields:
- { type: 0, family: IPv4 }
- { type: 3, family: IPv4 }
- { type: 8, family: IPv4 }
- { type: 11, family: IPv4 }
- { type: 12, family: IPv4 }
- { type: 1, family: IPv6 }
- { type: 2, family: IPv6 }
- { type: 3, family: IPv6 }
- { type: 4, family: IPv6 }
- { type: 128, family: IPv6 }
- { type: 129, family: IPv6 }
- { type: 133, family: IPv6 }
- { type: 134, family: IPv6 }
- { type: 135, family: IPv6 }
- { type: 136, family: IPv6 }
- { type: 143, family: IPv6 }
---
# Outbound HTTPS: OIDC discovery/token/JWKS at auth.renner.uno (Traefik VIP, matched as traefik
# pods above) and JetBrains services (license, update check), mail-free.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: youtrack-egress-https
namespace: youtrack
spec:
endpointSelector: {}
egress:
- toEntities:
- world
toPorts:
- ports:
- port: "443"
protocol: TCP
@@ -369,3 +369,23 @@ spec:
labelSelector:
matchLabels:
app.kubernetes.io/name: synapse
---
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: youtrack-daily
namespace: velero
labels:
app.kubernetes.io/part-of: homelab-backup
spec:
# Daily at 10:15 local, next free stagger slot after matrix-daily at 09:45.
schedule: "15 10 * * *"
useOwnerReferencesInBackup: false
template:
includedNamespaces:
- youtrack
includedResources:
- persistentvolumeclaims
storageLocation: default
ttl: 720h0m0s
snapshotMoveData: true
@@ -0,0 +1,4 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- restore.yaml
+7
View File
@@ -0,0 +1,7 @@
apiVersion: velero.io/v1
kind: Restore
metadata:
name: youtrack
namespace: velero
spec:
scheduleName: youtrack-daily