1
0

Compare commits

...

13 Commits

Author SHA1 Message Date
lukas 9fb6c4cc7c vaultwarden: fix formatting 2026-06-18 23:01:35 +02:00
lukas 1e623a9540 timetracker: migrate to newever version 2026-06-18 23:01:26 +02:00
lukas 33b89cb484 Add staging reaper for timetracker branch deployments
Removes timetracker staging containers/volumes/images whose branch no
longer exists on Gitea. Backstop for missed branch-delete events from
the staging workflow in the timetracker repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 17:08:55 +02:00
lukas 5aa85b0920 secrets: migrate exposed plaintext secrets to git-crypt
Move all hardcoded credentials out of tracked compose/env files into the
git-crypt-encrypted secrets/ directory, using each app's supported mechanism:

- env_file -> secrets/*.env: mealie, navidrome, karakeep, meilisearch,
  baserow, maloja, valheim, photoprism, komf, openldap, penpot, vaultwarden
- file:///run/secrets: authentik email password
- jelu DB password appended to existing secrets/jelu.env

Untrack root .env (interpolated ${VAR} secrets) and add sanitized
.env.example template; gitignore /.env.

Move unreferenced orphan files (mediawiki/rtorrent/snibox .env) into
secrets/ to preserve values while encrypting them.

Add SECURITY.md documenting the secrets conventions and a rotation
checklist. NOTE: all migrated values remain in prior git history and
must be rotated at their providers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 13:15:25 +02:00
lukas d35a9cf672 navidrome: auth workaround 2026-06-12 11:51:36 +02:00
lukas 72406c0000 polaris: add 2026-06-12 11:51:27 +02:00
lukas 2fece90ad2 yamtrack: update 2026-06-12 11:51:23 +02:00
lukas ef214f03aa slskd: update 2026-06-12 11:51:18 +02:00
lukas b20474b7b5 authentik: update 2026-06-12 11:51:12 +02:00
lukas 41c92dc6e7 use different chrome image 2026-06-12 11:51:07 +02:00
lukas e107be3474 karakeep: update ai conf 2026-06-12 11:50:58 +02:00
lukas ab1a6336aa rss-bridge: use labels 2026-06-12 11:50:48 +02:00
lukas 913e7ba387 add qui 2026-06-12 11:50:38 +02:00
34 changed files with 271 additions and 58 deletions
+4 -4
View File
@@ -21,16 +21,16 @@ PHOTOS_STORAGE_PATH=/srv/dev-disk-by-uuid-2d34f1a9-4284-4cad-ae9a-f1ef36244201/p
EMAIL_ADMIN=lukas@kucharczyk.xyz EMAIL_ADMIN=lukas@kucharczyk.xyz
EMAIL_FROM=kucharczyk.lukas@gmail.com EMAIL_FROM=kucharczyk.lukas@gmail.com
EMAIL_HOST=smtp.gmail.com EMAIL_HOST=smtp.gmail.com
EMAIL_PASSWORD=sebrubdsgkuptcjr EMAIL_PASSWORD=
EMAIL_PORT=587 EMAIL_PORT=587
POSTGRES_HOST=postgres POSTGRES_HOST=postgres
POSTGRES_USER=lukas POSTGRES_USER=lukas
POSTGRES_PASSWORD=kralovna POSTGRES_PASSWORD=
POSTGRES_PORT=5432 POSTGRES_PORT=5432
MYSQL_HOST=mariadb MYSQL_HOST=mariadb
MYSQL_USER=lukas MYSQL_USER=lukas
MYSQL_PASSWORD=kralovna MYSQL_PASSWORD=
MYSQL_ROOT_PASSWORD=kralovna MYSQL_ROOT_PASSWORD=
MYSQL_PORT=3306 MYSQL_PORT=3306
PUID=1000 PUID=1000
PGID=100 PGID=100
+2
View File
@@ -1 +1,3 @@
git-crypt-key git-crypt-key
# Real environment file with secrets; use .env.example as the template
/.env
+91
View File
@@ -0,0 +1,91 @@
# Security: secrets handling & rotation checklist
## How secrets are stored in this repo
- **`secrets/`** — git-crypt encrypted (see `.gitattributes`: `secrets/** filter=git-crypt`).
All real credentials live here. The working-tree copies are plaintext (git-crypt
only encrypts the committed blobs), so Docker reads them normally.
- **Root `.env`** — git-ignored (`/.env`) and **not** committed. It holds non-secret
config (ports, paths, domains) plus a few `${VAR}` values interpolated across
services. Use **`.env.example`** as the template; fill in the blanked secret values
locally.
- **Tracked compose / `*.env` files** — must contain **no secret values**. Pull secrets
in via one of:
- `env_file: - secrets/<svc>.env` (universal)
- `FILE__VARNAME=/run/secrets/<name>` (LinuxServer.io images, e.g. calibre-web-automated)
- `VARNAME_FILE=/run/secrets/<name>` (miniflux, gitea-runner, …)
- `file:///run/secrets/<name>` (authentik)
## Before you commit
```sh
# git-crypt must be unlocked so secrets/ files encrypt on commit
git-crypt status | grep -i 'not encrypted' || echo "all secrets/ files encrypted"
```
Quick scan for accidental plaintext secrets in tracked files:
```sh
git ls-files | grep -vE '^secrets/|^\.env\.example$' | xargs grep -nIE \
'(PASSWORD|SECRET|TOKEN|API_?KEY|CLIENT_SECRET|MASTER_KEY)=[^ ]' 2>/dev/null \
| grep -vE '_FILE|/run/secrets/|file:///|\$\{|=\s*$'
```
## Rotation checklist
All values below were committed to git history in plaintext before the 2026-06-12
migration. Migrating them to `secrets/` only protects them **going forward** — each
must be **rotated at its provider**, then history scrubbed (see bottom).
Tick each once the credential has been regenerated and the new value written to the
corresponding `secrets/` file.
### External / high priority (reachable beyond the LAN)
- [ ] **Gmail app password**`EMAIL_PASSWORD` in `.env` (reused by vaultwarden, mealie, baserow SMTP). Regenerate at Google Account → App passwords.
- [ ] **ProtonMail SMTP token**`secrets/authentik_email_password`. Regenerate in Proton → SMTP submission.
- [ ] **mealie OIDC client secret**`secrets/mealie.env`. Rotate the `mealie` provider in Authentik.
- [ ] **Last.fm API key + secret**`secrets/navidrome.env`. Reissue at last.fm/api/accounts.
- [ ] **Meilisearch master key**`secrets/meilisearch.env` (used by karakeep + meilisearch). Generate a new random key.
- [ ] **karakeep `NEXTAUTH_SECRET`**`secrets/karakeep.env`. `openssl rand -base64 36`.
- [ ] **vaultwarden `ADMIN_TOKEN`**`secrets/vaultwarden.env`. Regenerate with `vaultwarden hash` (Argon2).
- [ ] **jelu `GOOGLE_API_KEY`**`secrets/jelu.env`. Rotate in Google Cloud console.
### Internal (LAN-only, still rotate — `kralovna` is reused widely)
- [ ] **Postgres password**`POSTGRES_PASSWORD` in `.env` (`kralovna`).
- [ ] **MySQL/MariaDB passwords**`MYSQL_PASSWORD`, `MYSQL_ROOT_PASSWORD` in `.env` (`kralovna`).
- [ ] **baserow DB password**`secrets/baserow.env`.
- [ ] **photoprism admin + DB passwords**`secrets/photoprism.env`.
- [ ] **jelu DB password**`secrets/jelu.env`.
- [ ] **komf komga password + Kavita API key**`secrets/komf.env`.
- [ ] **openldap admin + readonly passwords**`secrets/openldap.env`.
- [ ] **maloja force password**`secrets/maloja.env`.
- [ ] **valheim server password**`secrets/valheim.env`.
- [ ] **penpot postgres password**`secrets/penpot.env`.
### Orphaned services (moved to `secrets/`; rotate if still running anywhere)
- [ ] **mediawiki MySQL password**`secrets/mediawiki.env`.
- [ ] **rtorrent RPC2 password**`secrets/rtorrent.env`.
- [ ] **snibox `SECRET_KEY_BASE`**`secrets/snibox.env`.
## Scrubbing git history
After rotating, remove the old plaintext values from history so the leaked secrets
become useless even to someone with an old clone:
```sh
# Using git-filter-repo (recommended). Removes the old tracked paths entirely.
git filter-repo --invert-paths \
--path .env \
--path mediawiki.env --path rtorrent.env --path snibox.env
# Then force-push and have every clone re-clone (rewritten history diverges):
git push --force --all
git push --force --tags
```
For surgical edits to lines inside files that stay tracked (e.g. a secret that lived
in `docker-compose.yml`), use `git filter-repo --replace-text <file>` with
`old==>***REMOVED***` rules, or BFG's `--replace-text`.
> Rotation is what actually neutralizes a leak. History scrubbing is best-effort —
> assume anything ever pushed is already compromised and rotate regardless.
+1 -1
View File
@@ -2,7 +2,7 @@ BASEROW_PUBLIC_URL=https://baserow.${DOMAIN}
DATABASE_HOST=${POSTGRES_HOST} DATABASE_HOST=${POSTGRES_HOST}
DATABASE_NAME=baserow DATABASE_NAME=baserow
DATABASE_USER=baserow DATABASE_USER=baserow
DATABASE_PASSWORD=S@8rBtSApf@YpNLXS!2hr2F$ # DATABASE_PASSWORD provided via secrets/baserow.env
EMAIL_SMTP=1 EMAIL_SMTP=1
EMAIL_SMTP_HOST=${EMAIL_HOST} EMAIL_SMTP_HOST=${EMAIL_HOST}
EMAIL_SMTP_PASSWORD=${EMAIL_PASSWORD} EMAIL_SMTP_PASSWORD=${EMAIL_PASSWORD}
+134 -30
View File
@@ -4,6 +4,8 @@ secrets:
file: secrets/gitea_runner_token.txt file: secrets/gitea_runner_token.txt
authentik_secret_key: authentik_secret_key:
file: secrets/authentik_secret_key file: secrets/authentik_secret_key
authentik_email_password:
file: secrets/authentik_email_password
email_host: email_host:
file: secrets/email_host file: secrets/email_host
email_username: email_username:
@@ -30,6 +32,8 @@ secrets:
file: secrets/igdb_api_client_secret file: secrets/igdb_api_client_secret
hardcover_api_token: hardcover_api_token:
file: secrets/hardcover_api_token file: secrets/hardcover_api_token
timetracker_secret_key:
file: secrets/timetracker_secret_key
configs: configs:
caddyfile: caddyfile:
@@ -62,6 +66,31 @@ configs:
root * /data/caddy/pki/authorities/local/ root * /data/caddy/pki/authorities/local/
file_server browse file_server browse
} }
music.home.arpa {
@ui_redirect {
not path /api/* /share/* /rest/*
}
# 1. API Auth: Use the new replace_status directive
forward_auth /api/* authentik-server:9000 {
uri /outpost.goauthentik.io/auth/caddy
copy_headers X-Authentik-Username
# Define a matcher for the 302 redirect from Authentik
@redir status 302
# Use the new Caddy 2.8 directive to swap it for a 401
replace_status @redir 401
}
# 2. Main UI Auth: Standard 302 redirects for human login
forward_auth @ui_redirect authentik-server:9000 {
uri /outpost.goauthentik.io/auth/caddy
copy_headers X-Authentik-Username
}
reverse_proxy navidrome:4533
}
dnsmasq: dnsmasq:
content: | content: |
log-facility=- log-facility=-
@@ -149,12 +178,15 @@ services:
timetracker: timetracker:
image: ${REGISTRY_URL}/timetracker image: ${REGISTRY_URL}/timetracker
container_name: timetracker container_name: timetracker
secrets:
- timetracker_secret_key
environment: environment:
- TZ=${TZ} - TZ=${TZ}
- "CSRF_TRUSTED_ORIGINS=https://tracker.kucharczyk.xyz" - "APP_URL=https://tracker.kucharczyk.xyz"
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
- DATA_DIR=/home/timetracker/app/data - DATA_DIR=/home/timetracker/app/data
- SECRET_KEY__FILE=/run/secrets/timetracker_secret_key
volumes: volumes:
- "${DOCKER_STORAGE_PATH}/timetracker/data:/home/timetracker/app/data" - "${DOCKER_STORAGE_PATH}/timetracker/data:/home/timetracker/app/data"
- "${DOCKER_STORAGE_PATH}/timetracker/backups:/home/timetracker/app/games/fixtures/backups" - "${DOCKER_STORAGE_PATH}/timetracker/backups:/home/timetracker/app/games/fixtures/backups"
@@ -263,7 +295,7 @@ services:
OIDC_PROVIDER_NAME: Authentik OIDC_PROVIDER_NAME: Authentik
OIDC_CONFIGURATION_URL: https://authentik.kucharczyk.xyz/application/o/mealie/.well-known/openid-configuration OIDC_CONFIGURATION_URL: https://authentik.kucharczyk.xyz/application/o/mealie/.well-known/openid-configuration
OIDC_CLIENT_ID: asDhzvutfxxpgwaaz0Jjr6SNpEtZo8GKjjs1WzUU OIDC_CLIENT_ID: asDhzvutfxxpgwaaz0Jjr6SNpEtZo8GKjjs1WzUU
OIDC_CLIENT_SECRET: iIgP3aaF1t0sTd8JPwXrCYmd3Ycc5hhfQROdHN7ByDU81gFJiNbRQ1OrTU7e9yzuPAyqLShRQ2Ve7ov03maHpQtyZzZ2FBdb0OHCkoS4brVuV8uZ4cnVPCzwLEO9bk9U # OIDC_CLIENT_SECRET provided via secrets/mealie.env
OIDC_SIGNUP_ENABLED: false OIDC_SIGNUP_ENABLED: false
OIDC_USER_GROUP: mealie-users OIDC_USER_GROUP: mealie-users
OIDC_ADMIN_GROUP: mealie-admins OIDC_ADMIN_GROUP: mealie-admins
@@ -272,6 +304,7 @@ services:
ALLOW_PASSWORD_LOGIN: false ALLOW_PASSWORD_LOGIN: false
env_file: env_file:
- mealie.env - mealie.env
- secrets/mealie.env
volumes: volumes:
- "${DOCKER_STORAGE_PATH}/mealie/data/:/app/data" - "${DOCKER_STORAGE_PATH}/mealie/data/:/app/data"
networks: networks:
@@ -307,6 +340,7 @@ services:
- ${DOCKER_STORAGE_PATH}/valheim/data:/opt/valheim - ${DOCKER_STORAGE_PATH}/valheim/data:/opt/valheim
env_file: env_file:
- valheim.env - valheim.env
- secrets/valheim.env
ports: ports:
- ${VALHEIM_EXTERNAL_PORT}:${VALHEIM_INTERNAL_PORT} - ${VALHEIM_EXTERNAL_PORT}:${VALHEIM_INTERNAL_PORT}
cap_add: cap_add:
@@ -355,7 +389,7 @@ services:
restart: unless-stopped restart: unless-stopped
navidrome: navidrome:
image: deluan/navidrome:0.61.2 image: ghcr.io/navidrome/navidrome:pr-5459
container_name: navidrome container_name: navidrome
user: "${PUID}:${PGID}" user: "${PUID}:${PGID}"
volumes: volumes:
@@ -364,16 +398,24 @@ services:
networks: networks:
public: public:
ipv4_address: 192.168.240.14 ipv4_address: 192.168.240.14
labels: # labels:
caddy: music.${DOMAIN_LOCAL} # caddy: music.${DOMAIN_LOCAL}
caddy.reverse_proxy: "{{ upstreams 4533 }}" # caddy.reverse_proxy: "{{ upstreams 4533 }}"
caddy.@protected.not.path: "/share/* /rest/*" # caddy.@protected.not.path: "/share/* /rest/*"
caddy.forward_auth_0: "@protected authentik-server:9000" # caddy.@authredir.path: "/api/*"
caddy.forward_auth_0.uri: "/outpost.goauthentik.io/auth/caddy" # caddy.@authredir.path: "/api/*"
caddy.forward_auth_0.copy_headers: "X-Authentik-Username" # caddy.forward_auth_0: "@protected authentik-server:9000"
# caddy.forward_auth_0.uri: "/outpost.goauthentik.io/auth/caddy"
# caddy.forward_auth_0.copy_headers: "X-Authentik-Username"
# caddy.intercept: "/api/*"
# caddy.@api_expiry.path: "/api/*"
# caddy.@api_expiry.status: "3xx"
# caddy.forward_auth_0.handle_response_0: "path /api/*"
# caddy.forward_auth_0.handle_response_1: "replace_status 401"
env_file:
- secrets/navidrome.env
environment: environment:
ND_LASTFM_APIKEY: 29e22ee836a0cb51cfaacb72d605e30d # ND_LASTFM_APIKEY / ND_LASTFM_SECRET provided via secrets/navidrome.env
ND_LASTFM_SECRET: 10aa58294eeffa142685e78a0cd78ad6
ND_DEEZER_ENABLED: true ND_DEEZER_ENABLED: true
ND_DEVACTIVITYPANEL: true ND_DEVACTIVITYPANEL: true
ND_ENABLESHARING: true ND_ENABLESHARING: true
@@ -395,6 +437,7 @@ services:
- "${MALOJA_EXTERNAL_PORT}:${MALOJA_INTERNAL_PORT}" - "${MALOJA_EXTERNAL_PORT}:${MALOJA_INTERNAL_PORT}"
env_file: env_file:
- maloja.env - maloja.env
- secrets/maloja.env
user: "${PUID}:${PGID}" user: "${PUID}:${PGID}"
volumes: volumes:
- "${DOCKER_STORAGE_PATH}/maloja:/data" - "${DOCKER_STORAGE_PATH}/maloja:/data"
@@ -574,6 +617,7 @@ services:
- mariadb - mariadb
env_file: env_file:
- photoprism.env - photoprism.env
- secrets/photoprism.env
volumes: volumes:
- "${PHOTOS_STORAGE_PATH}/import:/photoprism/import" - "${PHOTOS_STORAGE_PATH}/import:/photoprism/import"
- "${PHOTOS_STORAGE_PATH}/originals:/photoprism/originals" - "${PHOTOS_STORAGE_PATH}/originals:/photoprism/originals"
@@ -619,6 +663,7 @@ services:
- postgres - postgres
env_file: env_file:
- baserow.env - baserow.env
- secrets/baserow.env
volumes: volumes:
- "${DOCKER_STORAGE_PATH}/baserow:/baserow/data" - "${DOCKER_STORAGE_PATH}/baserow:/baserow/data"
restart: unless-stopped restart: unless-stopped
@@ -683,7 +728,7 @@ services:
# PUSH_INSTALLATION_KEY= # PUSH_INSTALLATION_KEY=
- PUSH_RELAY_URI=https://api.bitwarden.eu - PUSH_RELAY_URI=https://api.bitwarden.eu
- PUSH_IDENTITY_URI=https://identity.bitwarden.eu - PUSH_IDENTITY_URI=https://identity.bitwarden.eu
- ADMIN_TOKEN=$$argon2id$$v=19$$m=65540,t=3,p=4$$aWJ2cVRvYUsySkM3M01TMTJJMnZqbUF0Wm1qRWhvd1B6Sk50Q1hwck96dz0$$FKjZ36E54pX2e0AE9OaDpiH43TyAyfVwr3IvracbqEA # ADMIN_TOKEN provided via secrets/vaultwarden.env
- SMTP_HOST=${EMAIL_HOST} - SMTP_HOST=${EMAIL_HOST}
- SMTP_FROM=${EMAIL_FROM} - SMTP_FROM=${EMAIL_FROM}
- SMTP_FROM_NAME="Bitwarden (bw.kucharczyk.xyz)" - SMTP_FROM_NAME="Bitwarden (bw.kucharczyk.xyz)"
@@ -723,6 +768,28 @@ services:
caddy.reverse_proxy: "{{ upstreams $QBITTORRENT_WEBUI_INTERNAL_PORT }}" caddy.reverse_proxy: "{{ upstreams $QBITTORRENT_WEBUI_INTERNAL_PORT }}"
restart: unless-stopped restart: unless-stopped
qui:
image: ghcr.io/autobrr/qui:latest
container_name: qui
depends_on:
- qbittorrent
volumes:
- ${DOCKER_STORAGE_PATH}/qbittorrent/qui:/config
# for automations that move/delete torrent files
- ${TORRENTS_SEED_PATH}:/seed
networks:
public:
ipv4_address: 192.168.240.71
labels:
caddy: qui.${DOMAIN_LOCAL}
caddy.reverse_proxy: "{{ upstreams 7476 }}"
environment:
QUI__AUTH_DISABLED: true
QUI__I_ACKNOWLEDGE_THIS_IS_A_BAD_IDEA: true
QUI__AUTH_DISABLED_ALLOWED_CIDRS: 192.168.240.0/24
restart: unless-stopped
# see https://github.com/FarisZR/Privacy-OCI # see https://github.com/FarisZR/Privacy-OCI
breezewiki: breezewiki:
container_name: breezewiki container_name: breezewiki
@@ -749,9 +816,10 @@ services:
ipv4_address: 192.168.240.57 ipv4_address: 192.168.240.57
volumes: volumes:
- ./config:/config - ./config:/config
ports:
- 3002:80
restart: unless-stopped restart: unless-stopped
labels:
caddy: rss-bridge.${DOMAIN_LOCAL}
caddy.reverse_proxy: "{{ upstreams 80 }}"
karakeep: karakeep:
container_name: karakeep container_name: karakeep
@@ -766,12 +834,14 @@ services:
- 3003:3000 - 3003:3000
env_file: env_file:
- .env - .env
- secrets/meilisearch.env
- secrets/karakeep.env
environment: environment:
LOG_LEVEL: debug LOG_LEVEL: debug
MEILI_ADDR: http://meilisearch:7700 MEILI_ADDR: http://meilisearch:7700
BROWSER_WEB_URL: http://chrome:9222 BROWSER_WEB_URL: http://chrome:9222
NEXTAUTH_SECRET: lB5mx3t9mdKclELtt+cs2pVBefB+8vD4dKuzhvUP+JzR9bL1 # NEXTAUTH_SECRET provided via secrets/karakeep.env
MEILI_MASTER_KEY: Cvu7m/RIGYQPiYcIrxacHFhbfLKfKq3wwSAWJPKVWQEauiIX # MEILI_MASTER_KEY provided via secrets/meilisearch.env
NEXTAUTH_URL: https://karakeep.${DOMAIN} NEXTAUTH_URL: https://karakeep.${DOMAIN}
DISABLE_SIGNUPS: TRUE DISABLE_SIGNUPS: TRUE
CRAWLER_VIDEO_DOWNLOAD: TRUE CRAWLER_VIDEO_DOWNLOAD: TRUE
@@ -779,12 +849,12 @@ services:
CRAWLER_FULL_PAGE_SCREENSHOT: TRUE CRAWLER_FULL_PAGE_SCREENSHOT: TRUE
CRAWLER_FULL_PAGE_ARCHIVE: TRUE CRAWLER_FULL_PAGE_ARCHIVE: TRUE
OPENAI_BASE_URL: http://100.84.157.12:8081/v1 OPENAI_BASE_URL: http://100.84.157.12:8081/v1
OPENAI_API_KEY: "sk-llama-swap" OPENAI_API_KEY: "sk-experimental"
INFERENCE_TEXT_MODEL: gemma-4-26B-A4B-it-UD-Q4_K_M INFERENCE_TEXT_MODEL: gemma-4-26B
INFERENCE_IMAGE_MODEL: qwen2.5-vl-7b INFERENCE_IMAGE_MODEL: Qwen2.5-VL-7B
INFERENCE_ENABLE_AUTO_TAGGING: TRUE INFERENCE_ENABLE_AUTO_TAGGING: TRUE
INFERENCE_ENABLE_AUTO_SUMMARIZATION: TRUE INFERENCE_ENABLE_AUTO_SUMMARIZATION: TRUE
INFERENCE_CONTEXT_LENGTH: 32000 INFERENCE_CONTEXT_LENGTH: 65536
# You almost never want to change the value of the DATA_DIR variable. # You almost never want to change the value of the DATA_DIR variable.
# If you want to mount a custom directory, change the volume mapping above instead. # If you want to mount a custom directory, change the volume mapping above instead.
@@ -797,14 +867,14 @@ services:
caddy.reverse_proxy: "{{ upstreams 3000 }}" caddy.reverse_proxy: "{{ upstreams 3000 }}"
chrome: chrome:
image: gcr.io/zenika-hub/alpine-chrome:124 image: chromedp/headless-shell:latest
restart: unless-stopped restart: unless-stopped
command: command:
- --no-sandbox - --no-sandbox
- --disable-gpu - --disable-gpu
- --disable-dev-shm-usage - --disable-dev-shm-usage
- --remote-debugging-address=0.0.0.0 # - --remote-debugging-address=0.0.0.0
- --remote-debugging-port=9222 # - --remote-debugging-port=9222
- --hide-scrollbars - --hide-scrollbars
networks: networks:
public: public:
@@ -817,9 +887,10 @@ services:
restart: unless-stopped restart: unless-stopped
env_file: env_file:
- .env - .env
- secrets/meilisearch.env
environment: environment:
MEILI_NO_ANALYTICS: "true" MEILI_NO_ANALYTICS: "true"
MEILI_MASTER_KEY: Cvu7m/RIGYQPiYcIrxacHFhbfLKfKq3wwSAWJPKVWQEauiIX # MEILI_MASTER_KEY provided via secrets/meilisearch.env
volumes: volumes:
- meilisearch:/meili_data - meilisearch:/meili_data
networks: networks:
@@ -835,6 +906,7 @@ services:
- authentik_secret_key - authentik_secret_key
- postgres_general_username - postgres_general_username
- postgres_general_password - postgres_general_password
- authentik_email_password
environment: environment:
AUTHENTIK_POSTGRESQL__HOST: postgres AUTHENTIK_POSTGRESQL__HOST: postgres
AUTHENTIK_POSTGRESQL__NAME: authentik AUTHENTIK_POSTGRESQL__NAME: authentik
@@ -844,12 +916,12 @@ services:
AUTHENTIK_EMAIL__HOST: smtp.protonmail.ch AUTHENTIK_EMAIL__HOST: smtp.protonmail.ch
AUTHENTIK_EMAIL__PORT: 587 AUTHENTIK_EMAIL__PORT: 587
AUTHENTIK_EMAIL__USERNAME: lukas@kucharczyk.xyz AUTHENTIK_EMAIL__USERNAME: lukas@kucharczyk.xyz
AUTHENTIK_EMAIL__PASSWORD: CQHMWAUWQG5FBJ2V AUTHENTIK_EMAIL__PASSWORD: file:///run/secrets/authentik_email_password
AUTHENTIK_EMAIL__USE_TLS: true AUTHENTIK_EMAIL__USE_TLS: true
AUTHENTIK_EMAIL__USE_SSL: false AUTHENTIK_EMAIL__USE_SSL: false
AUTHENTIK_EMAIL__TIMEOUT: 60 AUTHENTIK_EMAIL__TIMEOUT: 60
AUTHENTIK_EMAIL__FROM: lukas@kucharczyk.xyz AUTHENTIK_EMAIL__FROM: lukas@kucharczyk.xyz
image: ghcr.io/goauthentik/server:2026.2.2 image: ghcr.io/goauthentik/server:2026.2.3
ports: ports:
- 9002:9000 - 9002:9000
- 9443:9443 - 9443:9443
@@ -893,7 +965,7 @@ services:
AUTHENTIK_EMAIL__USE_SSL: false AUTHENTIK_EMAIL__USE_SSL: false
AUTHENTIK_EMAIL__TIMEOUT: 60 AUTHENTIK_EMAIL__TIMEOUT: 60
AUTHENTIK_EMAIL__FROM: file:///run/secrets/email_username AUTHENTIK_EMAIL__FROM: file:///run/secrets/email_username
image: ghcr.io/goauthentik/server:2026.2.2 image: ghcr.io/goauthentik/server:2026.2.3
restart: unless-stopped restart: unless-stopped
user: root user: root
volumes: volumes:
@@ -957,7 +1029,7 @@ services:
- gpu - gpu
slskd: slskd:
image: slskd/slskd:0.24.0 image: slskd/slskd:0.25.1
container_name: slskd container_name: slskd
user: 1000:100 user: 1000:100
networks: networks:
@@ -975,6 +1047,7 @@ services:
- SLSKD_SHARED_DIR=/shares - SLSKD_SHARED_DIR=/shares
- SLSKD_SLSK_ADDRESS=server.slsknet.org - SLSKD_SLSK_ADDRESS=server.slsknet.org
- SLSKD_SLSK_PORT=2242 - SLSKD_SLSK_PORT=2242
- SLSKD_DEBUG=True
# from slskd_secrets.env # from slskd_secrets.env
# - SLSKD_USERNAME # - SLSKD_USERNAME
# - SLSKD_PASSWORD # - SLSKD_PASSWORD
@@ -1031,7 +1104,7 @@ services:
yamtrack: yamtrack:
container_name: yamtrack container_name: yamtrack
image: ghcr.io/fuzzygrim/yamtrack:0.25.2 image: ghcr.io/fuzzygrim/yamtrack:0.25.3
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- redis - redis
@@ -1068,6 +1141,37 @@ services:
caddy: yamtrack.${DOMAIN_LOCAL} caddy: yamtrack.${DOMAIN_LOCAL}
caddy.reverse_proxy: "{{ upstreams 8000 }}" caddy.reverse_proxy: "{{ upstreams 8000 }}"
polaris:
image: registry.gitlab.com/connectical/container/polaris:latest
container_name: polaris
restart: unless-stopped
user: "${PUID}:${PGID}"
networks:
public:
ipv4_address: 192.168.240.70
ports:
- 5050:5050
labels:
caddy: polaris.${DOMAIN_LOCAL}
caddy.reverse_proxy: "{{ upstreams 5050 }}"
volumes:
- ${MUSIC_PATH}:/music:ro
- ${DOCKER_STORAGE_PATH}/polaris/cache:/var/cache/polaris
- ${DOCKER_STORAGE_PATH}/polaris/data:/var/lib/polaris
signal-cli:
image: bbernhard/signal-cli-rest-api
container_name: signal-cli
restart: unless-stopped
networks:
public:
ipv4_address: 192.168.240.72
ports:
- 8091:8080
volumes:
- ${DOCKER_STORAGE_PATH}/signal-cli:/home/.local/share/signal-cli
environment:
MODE: native
networks: networks:
+1 -1
View File
@@ -1,2 +1,2 @@
MALOJA_DATA_DIRECTORY=/data MALOJA_DATA_DIRECTORY=/data
MALOJA_FORCE_PASSWORD=kralovna # MALOJA_FORCE_PASSWORD provided via secrets/maloja.env
-3
View File
@@ -1,3 +0,0 @@
MYSQL_DATABASE=mediawiki
MYSQL_USER=mediawiki
MYSQL_PASSWORD=41eebea0e3ef17dc68064e004e03dafeddd996bf513021b5cf7daf5a0c4d2b32
+3 -1
View File
@@ -56,11 +56,13 @@ services:
restart: always restart: always
stop_signal: SIGINT stop_signal: SIGINT
env_file:
- secrets/penpot.env
environment: environment:
- POSTGRES_INITDB_ARGS=--data-checksums - POSTGRES_INITDB_ARGS=--data-checksums
- POSTGRES_DB=penpot - POSTGRES_DB=penpot
- POSTGRES_USER=penpot - POSTGRES_USER=penpot
- POSTGRES_PASSWORD=penpot # POSTGRES_PASSWORD provided via secrets/penpot.env
volumes: volumes:
- penpot_postgres_data:/var/lib/postgresql/data - penpot_postgres_data:/var/lib/postgresql/data
+2 -2
View File
@@ -1,7 +1,7 @@
PHOTOPRISM_ADMIN_PASSWORD=kRalovna12514265! # PHOTOPRISM_ADMIN_PASSWORD provided via secrets/photoprism.env
PHOTOPRISM_DATABASE_DRIVER=mysql PHOTOPRISM_DATABASE_DRIVER=mysql
PHOTOPRISM_DATABASE_NAME=photoprism PHOTOPRISM_DATABASE_NAME=photoprism
PHOTOPRISM_DATABASE_PASSWORD=TWB64mcPZ^TSdo # PHOTOPRISM_DATABASE_PASSWORD provided via secrets/photoprism.env
PHOTOPRISM_DATABASE_SERVER=mariadb PHOTOPRISM_DATABASE_SERVER=mariadb
PHOTOPRISM_DATABASE_USER=photoprism PHOTOPRISM_DATABASE_USER=photoprism
PHOTOPRISM_IMPORT_PATH=/photoprism/import PHOTOPRISM_IMPORT_PATH=/photoprism/import
-6
View File
@@ -1,6 +0,0 @@
VPN_ENABLED=no
ENABLE_WEBUI_AUTH=no
ENABLE_RPC2=yes
ENABLE_RPC2_AUTH=yes
RPC2_USER=lukas
RPC2_PASS=5zpxni8N@DYCaZL
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Removes timetracker staging containers (deployed by .gitea/workflows/staging.yml
# in the timetracker repo) whose branch no longer exists on Gitea.
# Backstop for missed branch-delete events; safe to run any time.
set -euo pipefail
API="https://git.kucharczyk.xyz/api/v1/repos/lukas/timetracker/branches?limit=50"
# If the API is unreachable, set -e aborts here and nothing gets reaped.
branches=$(curl -fsS "$API" | python3 -c 'import json,sys; print("\n".join(b["name"] for b in json.load(sys.stdin)))')
docker ps -a --filter label=xyz.kucharczyk.staging=timetracker --format '{{.Names}}' | while read -r name; do
branch=$(docker inspect "$name" --format '{{ index .Config.Labels "xyz.kucharczyk.staging.branch" }}')
if ! grep -qxF "$branch" <<<"$branches"; then
image=$(docker inspect "$name" --format '{{ .Config.Image }}')
docker rm -f "$name" >/dev/null
docker volume rm "$name" >/dev/null 2>&1 || true
docker rmi "$image" >/dev/null 2>&1 || true
echo "reaped ${name} (branch '${branch}' no longer exists)"
fi
done
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -19,7 +19,7 @@ services:
environment: environment:
SERVER_PORT: 80 SERVER_PORT: 80
SPRING_DATASOURCE_USERNAME: lukas SPRING_DATASOURCE_USERNAME: lukas
SPRING_DATASOURCE_PASSWORD: Q^k5i2^hN!wmEr6JLkYP9ME # SPRING_DATASOURCE_PASSWORD provided via secrets/jelu.env
JELU_CORS_ALLOWED-ORIGINS: https://jelu.${DOMAIN} JELU_CORS_ALLOWED-ORIGINS: https://jelu.${DOMAIN}
restart: unless-stopped restart: unless-stopped
+5 -3
View File
@@ -45,7 +45,7 @@ configs:
kavita: kavita:
baseUri: "http://localhost:5000" #or env:KOMF_KAVITA_BASE_URI baseUri: "http://localhost:5000" #or env:KOMF_KAVITA_BASE_URI
apiKey: "16707507-d05d-4696-b126-c3976ae14ffb" #or env:KOMF_KAVITA_API_KEY apiKey: # set via env:KOMF_KAVITA_API_KEY (secrets/komf.env)
eventListener: eventListener:
enabled: false # if disabled will not connect to kavita and won't pick up newly added entries enabled: false # if disabled will not connect to kavita and won't pick up newly added entries
metadataLibraryFilter: [ ] # listen to all events if empty metadataLibraryFilter: [ ] # listen to all events if empty
@@ -194,12 +194,14 @@ services:
user: 1000:100 user: 1000:100
ports: ports:
- "8085:8085" - "8085:8085"
env_file:
- ../secrets/komf.env
environment: environment:
- KOMF_KOMGA_BASE_URI=http://komga:25600 - KOMF_KOMGA_BASE_URI=http://komga:25600
- KOMF_KOMGA_USER=lukas@kucharczyk.xyz - KOMF_KOMGA_USER=lukas@kucharczyk.xyz
- KOMF_KOMGA_PASSWORD=kRalovna12514265! # KOMF_KOMGA_PASSWORD provided via secrets/komf.env
- KOMF_KAVITA_BASE_URI=http://kavita:${KAVITA_INTERNAL_PORT} - KOMF_KAVITA_BASE_URI=http://kavita:${KAVITA_INTERNAL_PORT}
- KOMF_KAVITA_API_KEY=c8023836-7aab-46ed-9409-c24b950002d4 # KOMF_KAVITA_API_KEY provided via secrets/komf.env
- KOMF_LOG_LEVEL=INFO - KOMF_LOG_LEVEL=INFO
- JAVA_TOOL_OPTIONS=-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact -XX:ShenandoahGuaranteedGCInterval=3600000 -XX:TrimNativeHeapInterval=3600000 - JAVA_TOOL_OPTIONS=-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact -XX:ShenandoahGuaranteedGCInterval=3600000 -XX:TrimNativeHeapInterval=3600000
configs: configs:
+4 -2
View File
@@ -12,13 +12,15 @@ services:
volumes: volumes:
- "${DOCKER_STORAGE_PATH}/openldap/config:/etc/ldap/slapd.d" - "${DOCKER_STORAGE_PATH}/openldap/config:/etc/ldap/slapd.d"
- "${DOCKER_STORAGE_PATH}/openldap/data:/var/lib/ldap" - "${DOCKER_STORAGE_PATH}/openldap/data:/var/lib/ldap"
env_file:
- ../secrets/openldap.env
environment: environment:
- LDAP_ORGANISATION=Homelab - LDAP_ORGANISATION=Homelab
- LDAP_DOMAIN=${DOMAIN} - LDAP_DOMAIN=${DOMAIN}
- LDAP_ADMIN_PASSWORD=kral # LDAP_ADMIN_PASSWORD provided via secrets/openldap.env
- LDAP_OPENLDAP_UID=${PUID} - LDAP_OPENLDAP_UID=${PUID}
- LDAP_OPENLDAP_GID=${PGID} - LDAP_OPENLDAP_GID=${PGID}
- LDAP_READONLY_USER=true - LDAP_READONLY_USER=true
- LDAP_READONLY_USER_USERNAME=readonly - LDAP_READONLY_USER_USERNAME=readonly
- LDAP_READONLY_USER_PASSWORD=readonly # LDAP_READONLY_USER_PASSWORD provided via secrets/openldap.env
restart: unless-stopped restart: unless-stopped
-2
View File
@@ -1,2 +0,0 @@
SECRET_KEY_BASE=sMHYqzrgJQgPynv6ZDG7M8ZpF
FORCE_SSL=false
+1 -1
View File
@@ -1,4 +1,4 @@
SERVER_NAME=LukasJirkaDominik SERVER_NAME=LukasJirkaDominik
WORLD_NAME=Mujnovyserver WORLD_NAME=Mujnovyserver
SERVER_PASS=heslo # SERVER_PASS provided via secrets/valheim.env
VALHEIM_PLUS=true VALHEIM_PLUS=true