From 29b57ab7cb0ab1a0c9c9261de843ddc24b81f278 Mon Sep 17 00:00:00 2001 From: Robert Günzler Date: Mon, 23 Feb 2026 14:30:47 +0100 Subject: deploy geopulse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Günzler --- bundles/authelia/files/configuration.yml | 1 + bundles/authelia/files/configuration_oidc.yml | 14 ++- bundles/geopulse/TODO | 2 + bundles/geopulse/files/kube.yaml | 148 ++++++++++++++++++++++++++ bundles/geopulse/files/secret.yaml | 13 +++ bundles/geopulse/items.py | 37 +++++++ bundles/geopulse/metadata.py | 13 +++ 7 files changed, 226 insertions(+), 2 deletions(-) create mode 100644 bundles/geopulse/TODO create mode 100644 bundles/geopulse/files/kube.yaml create mode 100644 bundles/geopulse/files/secret.yaml create mode 100644 bundles/geopulse/items.py create mode 100644 bundles/geopulse/metadata.py diff --git a/bundles/authelia/files/configuration.yml b/bundles/authelia/files/configuration.yml index 39cf40f..1760493 100644 --- a/bundles/authelia/files/configuration.yml +++ b/bundles/authelia/files/configuration.yml @@ -22,6 +22,7 @@ access_control: - 'paper.gzr.im' - 'tv.gzr.im' - 'photos.gzr.im' + - 'where.gzr.im' policy: 'one_factor' # 2factor is a sane default - domain: diff --git a/bundles/authelia/files/configuration_oidc.yml b/bundles/authelia/files/configuration_oidc.yml index 34280d3..1299955 100644 --- a/bundles/authelia/files/configuration_oidc.yml +++ b/bundles/authelia/files/configuration_oidc.yml @@ -5,6 +5,10 @@ identity_providers: - key: |- ${repo.libs.util.indent(repo.vault.decrypt("encrypt$gAAAAABnOUxLHGPI8B_65SL7obl2v4_3E8J1i271tq-JfX2ohlz8PLydbQRI-wJlg-4kqm3Bp1jkH5BXa92KP9ZEseqadX7uLWU-9cVKj8WAUNlC3VoBFubNRb_crVKOavI3zCJd_9--CpTVCdR062EaR8AJUeiTLkTx8DU2CcaMFKLQ1nuUA4tpEk8dyVhvwtlbm8ItjCdvfl-CTBVE3LoczY6E_I35bKEcDvT_fS1Y6fDFV2S6PxRQSWLByfwsVFMkkHza1gNqvejaNggHxI-hjzlCHPdjlgpRBhd9Sd-Zs3u8PU5GhShhc2SlRv640QBzfrAcxckMDlYUcgvkcp38AiDF9rKgQiUfYSoHIg8dJJMP8pYHGYSIdCZQY7tw5Pdge_xVAEM3KIiIh6IPRm3iJ8ZG4HFq0Xjh42T86BCcYUsY_RGBBKaygf4UvDotlb3Np5v9mYc7jun8Z-DrGmEt6a5fHw9JlmFpbDaqp-pLzv9aq9TD9yGB-hisLTJbEjp3VzOc5GPhROH5qYxbeHqoisGeETNI575tOnS_MN-skJlWU2Uaglep1wH4gWyWRQqA-Xb5d2LZYenMldJ7DJhFCO8XgAcFgQrdma1MlmumEUmQYuM0IeOhq862rnO1UgQQ_gXOVyT4yYUSK3C0-s28slkN3b82tyyl7YzNKQpyUHGTIsKlDIpntX_TTy78wBJLjmF8C8RphZCixOFgrEvt8puBDvBLlJDkq4xgJTkExYsTsZaG-TJxXYtIR-yfWgTiMKnflFYK6um-JsaaIVfeKtcRdVao70V9vRaDER5DWE1XCCXWQru0BBMBbv_qpDeHYrjgZrkEhZZeXgveS-2f5PMlFFRhTkXRj-8qe9cO3qBsoZOBxLCCs_-ueyNH7jqw8_Yn8H-qrt5KI8MuKXTqwjQpbeW2JXiqusiqrVQElx3efNoCohdXtvSyTD7D-UriPij85he8sDJv_YouScHb3ItGbJrv0mPiAUO0iX_XA0I6Ck2jETlc6brzzmyKc23pdj-clkWZENouaiitoiYKECIlergumMmId0WjcMiXpA0Jwe8rfPT4S2QiemUsiM1u5SMkI6eSL8uQTUr_kavlUFV3r3yZqeQk1SpGT2hB_iMkqcNzliwk6J6n_ohqEzC8IP1yM4EzFKh2P2Q1n_Ro2MZsk7wjjLdm32895b_0o3FF-4pA4NSm0UZ-kvibebn-8TVhv2eRn-DsWgtzXDxWtAwBUtHKtQX6MZQVuswTZTSSuh6piQV4AnKaGpr7Gt1G0-VUG8QI9uuc-hBdwuZbS-q_d19UGabJxAw1Ssh3UOA__Bfhc9_2TZ2a6VKfzXih1-mxFQfA0EQJ4E4cktFfv6YEOlFsJ6ayfaCEJM4UhmuArKWLidaOnRVgO3qn-GG-p-q294O4Z1GSD8gddVrfdOymHRBjPbVMRvvQCUzvEdrt_oAqUWhG5ZenS6jF2aLZtDMVu-E87GKYKEDFSwybMRlEfiAS6GEySUB9MEGqrskf-u_esVv2U-luDV1GBhXi08n8RsLjOScEc59iZMC1CEFM0tG1kAPIE-57XK-Ja0tw3TofMXa6xauL8CnFMqYhdPTwUHeTwv7LM9n3kFksjAFcYAp8TeI-NPktswjFBsRaBc1-55BUJfhzKzL-DPJLHI_O7H9GhaSKlO0HGKcR7iUayR_GHfhdkAEZIdd5qXKOUIvd5o4n1klXrN1svBpRODlN3bmC6t9EmFYTSGSZNfNqrRrS7JNBioM0INuVQyqFXBqeavlTvSStEAaJxtCegt5bsqWNpuvQA06b7xyTcqiaQ8CaB9RzOx-xI7Vii0y-1gTjq35_rpndvNqVZC_hpPpTt-4ZQVJAmzYPZ6TIsiBcUTnOc1fRUEV1PtVJm0KhHWV_GNrHdkiHsmNtb759gKHo16-k2eyvOTUEXNwMRgQ3_U9PV2qXxoiAfiKFbgSDIy4qSdhsm2C4VREmlspkNEMgy6JB2QGygzrOs4uOS1p4lcbKvmhVllqqLyQ9nW_FkjkeibVQHvlKGX7V-NoFlWeyJ15XOupRb-3Wh8ibjOMD8IlX9vIhTJSJh54fy9DbrCo-UR8BIpP7JT0FeTKcbmjtmS7TuyRO8jpSqdiRys_rT-Ebgc-sq77uLpNBN1YBZU0VB848tSKM30Nl2wl-o9NBVh8tjGF8NsJyCoF0lR4w1rvVURNPj7dKsn6w_Qz4QKrTtUIo8jYkBy_VwbySJz6aN2CUM66_2h6_wxwopGaCYV18p3lhBe7u5WwqrCJ563b2VW7NBE5MD1AZbOCKmOWBSdnZud7Ee2U6nNr9jeAyDTCaut4NSS-ecDqnrDYxp9SSXVY="), " "*10, "not_first")} + claims_policies: + geopulse: + id_token: ['email'] + clients: - client_id: jellyfin client_name: 'Jellyfin' @@ -35,5 +39,11 @@ identity_providers: - https://photos.gzr.im/api/oauth/mobile-redirect - app.immich:///oauth-callback # required since immich v1.113.0 - # consent_mode: pre-configured - # pre_configured_consent_duration: 1w + - client_id: geopulse + client_name: 'GeoPulse' + client_secret: '${repo.libs.util.hash_bcrypt(repo.vault.password_for("authelia_client_secret_geopulse"), repo.vault.decrypt("encrypt$gAAAAABnOVCVoszwYPX_uTEIrMSyX94T_Mi8965InBlhKjkNBHMnN96ihiIt4yi8uYRl9DM70aPIwzXm2XVa_AXEEuIzbMJHBum6LTVDDE9CUYUErSFskMw="))}' + authorization_policy: one_factor + token_endpoint_auth_method: client_secret_post + redirect_uris: + - https://where.gzr.im/oidc/callback + claims_policy: geopulse diff --git a/bundles/geopulse/TODO b/bundles/geopulse/TODO new file mode 100644 index 0000000..6affd5e --- /dev/null +++ b/bundles/geopulse/TODO @@ -0,0 +1,2 @@ +https://github.com/tess1o/geopulse/blob/main/docker-compose.yml +VERSINO=1.1.2 diff --git a/bundles/geopulse/files/kube.yaml b/bundles/geopulse/files/kube.yaml new file mode 100644 index 0000000..b10bc7f --- /dev/null +++ b/bundles/geopulse/files/kube.yaml @@ -0,0 +1,148 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: geopulse +data: + GEOPULSE_UI_URL: https://where.gzr.im + GEOPULSE_AUTH_SECURE_COOKIES: true + GEOPULSE_AUTH_REGISTRATION_ENABLED: true + GEOPULSE_AUTH_OIDC_REGISTRATION_ENABLED: true + GEOPULSE_AUTH_PASSWORD_REGISTRATION_ENABLED: false + GEOPULSE_BACKEND_URL: http://localhost:8080 + GEOPULSE_OIDC_ENABLED: true + GEOPULSE_OIDC_PROVIDER_GENERIC_ENABLED: true + GEOPULSE_OIDC_PROVIDER_GENERIC_NAME: login.gzr.im + GEOPULSE_OIDC_PROVIDER_GENERIC_DISCOVERY_URL: https://login.gzr.im/.well-known/openid-configuration + GEOPULSE_OIDC_PROVIDER_GENERIC_ICON: pi pi-lock + OSM_RESOLVER: 127.0.0.11 9.9.9.9 + # GEOPULSE_GEOCODING_DELAY_MS: 1000 + GEOPULSE_GEOCODING_PRIMARY_PROVIDER: nominatim + GEOPULSE_GEOCODING_FALLBACK_PROVIDER: photon + GEOPULSE_GEOCODING_PHOTON_ENABLED: true + GEOPULSE_GEOCODING_NOMINATIM_ENABLED: true + # GEOPULSE_SHARE_BASE_URL: + GEOPULSE_MQTT_ENABLED: false +--- +apiVersion: v1 +kind: Pod +metadata: + name: geopulse + labels: + traefik.enable: true + traefik.http.routers.geopulse.tls: true + traefik.http.routers.geopulse.tls.certresolver: le + traefik.http.routers.geopulse.entrypoints: http,https + traefik.http.routers.geopulse.rule: Host(`where.gzr.im`) + traefik.http.routers.geopulse.service: geopulse + traefik.http.services.geopulse.loadbalancer.server.port: 80 + # metrics + traefik.http.middlewares.replacepath-metrics-geopulse.replacepath.path: /api/prometheus/metrics + traefik.http.routers.geopulse-metrics.entrypoints: metrics + traefik.http.routers.geopulse-metrics.rule: Path(`/metrics/geopulse`) + traefik.http.routers.geopulse-metrics.middlewares: replacepath-metrics-geopulse +spec: + restartPolicy: Never + dnsPolicy: Default + containers: + - name: backend + image: ghcr.io/tess1o/geopulse-backend:${version}-native + restartPolicy: OnFailure + envFrom: + - secretRef: + name: geopulse + - configMapRef: + name: geopulse + volumeMounts: + - name: keys + mountPath: /app/keys + readOnly: true + ports: + - containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: /api/health + port: 8080 + initialDelaySeconds: 20 + resources: + limits: + memory: 512Mi + + - name: ui + image: ghcr.io/tess1o/geopulse-ui:${version} + envFrom: + - secretRef: + name: geopulse + - configMapRef: + name: geopulse + ports: + - containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: 80 + initialDelaySeconds: 5 + resources: + limits: + memory: 256Mi + + - name: postgres + image: index.docker.io/postgis/postgis:17-3.5 + ports: + - containerPort: 5432 + hostIP: 100.82.12.64 + hostPort: 25432 + volumeMounts: + - name: pg-data + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: geopulse + - configMapRef: + name: geopulse + livenessProbe: + exec: + command: ["pg_isready", "-U", "geopulse"] + initialDelaySeconds: 5 + resources: + limits: + memory: 128Mi + # Conservative PostgreSQL settings optimized for minimal resource usage + # Suitable for small deployments and idle GPS tracking workloads + args: + - -c + - shared_buffers=256MB + - -c + - work_mem=8MB + - -c + - maintenance_work_mem=64MB + - -c + - effective_cache_size=1GB + - -c + - max_wal_size=512MB + - -c + - checkpoint_completion_target=0.9 + - -c + - wal_buffers=16MB + - -c + - random_page_cost=1.1 + - -c + - effective_io_concurrency=100 + - -c + - autovacuum_naptime=60s + - -c + - autovacuum_vacuum_scale_factor=0.2 + - -c + - log_min_duration_statement=5000 + - -c + - track_io_timing=on + volumes: + - name: keys + hostPath: + path: /var/lib/geopulse/keys + type: Directory + - name: pg-data + hostPath: + path: /var/lib/geopulse/data + type: DirectoryOrCreate diff --git a/bundles/geopulse/files/secret.yaml b/bundles/geopulse/files/secret.yaml new file mode 100644 index 0000000..29de6fb --- /dev/null +++ b/bundles/geopulse/files/secret.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Secret +metadata: + name: geopulse +data: + POSTGRES_USER: ${repo.libs.util.base64("geopulse")} + POSTGRES_PASSWORD: ${repo.vault.password_for("geopulse_db_pw").b64encode().value} + POSTGRES_DB: ${repo.libs.util.base64("geopulse")} + GEOPULSE_OIDC_PROVIDER_GENERIC_CLIENT_ID: ${repo.libs.util.base64("geopulse")} + GEOPULSE_OIDC_PROVIDER_GENERIC_CLIENT_SECRET: ${repo.vault.password_for("authelia_client_secret_geopulse").b64encode().value} + GEOPULSE_POSTGRES_USERNAME: ${repo.libs.util.base64("geopulse")} + GEOPULSE_POSTGRES_PASSWORD: ${repo.vault.password_for("geopulse_db_pw").b64encode().value} + GEOPULSE_POSTGRES_URL: ${repo.libs.util.base64(f"jdbc:postgresql://localhost/geopulse")} diff --git a/bundles/geopulse/items.py b/bundles/geopulse/items.py new file mode 100644 index 0000000..f9fa882 --- /dev/null +++ b/bundles/geopulse/items.py @@ -0,0 +1,37 @@ +directories = { + "/var/lib/geopulse": {}, +} + +files = { + "/etc/deployments/geopulse/kube.yaml": { + "content_type": "mako", + "context": node.metadata.get("containers")["geopulse"], + "triggers": {"svc_s6rc:geopulse:restart"}, + }, + "/etc/deployments/geopulse/secret.yaml": { + "content_type": "mako", + "mode": "0600", + "triggers": {"svc_s6rc:geopulse:restart"}, + }, +} + +actions = { + "keygen": { + "command": """ + set -ex + cd /var/lib/geopulse/ + curl -sSfL https://raw.githubusercontent.com/tess1o/geopulse/refs/tags/1.2.0/generate-keys.sh | + sed -e 's|KEYS_DIR="/keys"|KEYS_DIR="./keys"|' | + sh - + """, + "unless": """ + cd /var/lib/geopulse/keys && + test -f jwt-private-key.pem && + test -f jwt-public-key.pem && + test -f ai-encryption-key.txt + """, + "needs": { + "directory:/var/lib/geopulse", + }, + }, +} diff --git a/bundles/geopulse/metadata.py b/bundles/geopulse/metadata.py new file mode 100644 index 0000000..21a55f6 --- /dev/null +++ b/bundles/geopulse/metadata.py @@ -0,0 +1,13 @@ +defaults = { + "backup": { + "includes": { + "/var/lib/geopulse", + } + }, + "containers": { + "geopulse": { + "version": "1.3.0", + }, + }, + "metrics": {"geopulse": {}}, +} -- cgit 1.4.1