Working NixOS port: all core services operational
- Fix Caddy cfProxy helper for cloudflared http:// vhosts (X-Forwarded-Proto) - Fix Authelia LDAP bind (readonly user ACL + password sync) - Add gitea-admin-setup oneshot service to survive rebuilds - Update Authelia forward_auth with header_up X-Forwarded-Proto https - Update TODO.org with completed tasks and LDAP config details - Remove old Helm/k8s artifacts (Chart.yaml, templates/, values/, scripts) - Add result to .gitignore Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,7 @@ let
|
||||
dataDir = config.homey.storage.mountPoint;
|
||||
domain = homeyConfig.domain;
|
||||
|
||||
# LDAP base DN derived from domain: home.zakobar.com → dc=home,dc=zakobar,dc=com
|
||||
# LDAP base DN derived from domain: zakobar.com → dc=zakobar,dc=com
|
||||
ldapBaseDN = lib.concatStringsSep ","
|
||||
(map (p: "dc=${p}") (lib.splitString "." domain));
|
||||
|
||||
@@ -162,7 +162,7 @@ in
|
||||
virtualisation.oci-containers.containers.authelia = {
|
||||
image = cfg.image;
|
||||
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:9091" ];
|
||||
# No ports mapping — --network=host shares the host network stack directly.
|
||||
|
||||
environment = {
|
||||
TZ = homeyConfig.timezone;
|
||||
|
||||
+149
-118
@@ -9,7 +9,15 @@
|
||||
# Volume layout:
|
||||
# <dataDir>/gitea/data/ → /data (repos, sqlite db, avatars, lfs, etc.)
|
||||
#
|
||||
# The app.ini is rendered by Nix and bind-mounted read-only.
|
||||
# Configuration strategy: all settings are passed as GITEA__<SECTION>__<KEY>
|
||||
# environment variables. Gitea writes its own app.ini into /data/gitea/conf/
|
||||
# on first start; the env vars override every key at runtime without touching
|
||||
# that file. This avoids the bind-mount / read-only-fs problem where Gitea
|
||||
# needs to rewrite its own config file on startup.
|
||||
#
|
||||
# Non-secret settings go in the `environment` block (they are fine in the
|
||||
# Nix store). Secret settings go into /run/gitea-secrets.env via ExecStartPre
|
||||
# (never in the store).
|
||||
#
|
||||
# Secrets consumed from sops:
|
||||
# gitea/admin_password
|
||||
@@ -21,98 +29,6 @@ let
|
||||
cfg = config.homey.gitea;
|
||||
dataDir = config.homey.storage.mountPoint;
|
||||
domain = homeyConfig.domain;
|
||||
|
||||
# Gitea app.ini — generated at build time.
|
||||
# Secrets that Gitea reads from env vars are referenced as env var names here.
|
||||
# The actual values are injected by the ExecStartPre wrapper below.
|
||||
giteaAppIni = ''
|
||||
APP_NAME = ${homeyConfig.organization}
|
||||
RUN_MODE = prod
|
||||
RUN_USER = git
|
||||
WORK_PATH = /data/gitea
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
|
||||
[server]
|
||||
APP_DATA_PATH = /data/gitea
|
||||
DOMAIN = git.${domain}
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = https://git.${domain}/
|
||||
DISABLE_SSH = true
|
||||
LFS_START_SERVER = true
|
||||
; LFS_JWT_SECRET injected at container start via env var / startup script
|
||||
LFS_JWT_SECRET = __GITEA_LFS_JWT_SECRET__
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[lfs]
|
||||
PATH = /data/git/lfs
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /data/gitea/gitea.db
|
||||
LOG_SQL = false
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
PROVIDER = file
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /data/gitea/avatars
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
|
||||
DISABLE_GRAVATAR = false
|
||||
|
||||
[attachment]
|
||||
PATH = /data/gitea/attachments
|
||||
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = info
|
||||
ROUTER = console
|
||||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
REVERSE_PROXY_LIMIT = 1
|
||||
REVERSE_PROXY_TRUSTED_PROXIES = *
|
||||
; INTERNAL_TOKEN injected at container start
|
||||
INTERNAL_TOKEN = __GITEA_INTERNAL_TOKEN__
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = true
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = true
|
||||
ENABLE_CAPTCHA = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.localhost
|
||||
ENABLE_REVERSE_PROXY_AUTHENTICATION = true
|
||||
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = true
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = false
|
||||
ENABLE_OPENID_SIGNUP = false
|
||||
|
||||
[oauth2]
|
||||
ENABLE = false
|
||||
; JWT_SECRET injected at container start
|
||||
JWT_SECRET = __GITEA_OAUTH2_JWT_SECRET__
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
options.homey.gitea = {
|
||||
@@ -139,60 +55,175 @@ in
|
||||
sops.secrets."gitea/oauth2_jwt_secret" = { owner = "root"; };
|
||||
sops.secrets."gitea/internal_token" = { owner = "root"; };
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Write the app.ini template to /etc (will be processed by ExecStartPre)
|
||||
# -----------------------------------------------------------------------
|
||||
environment.etc."gitea/app.ini.tpl" = {
|
||||
text = giteaAppIni;
|
||||
mode = "0444";
|
||||
};
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Container
|
||||
# -----------------------------------------------------------------------
|
||||
virtualisation.oci-containers.containers.gitea = {
|
||||
image = cfg.image;
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:3000" ];
|
||||
# No ports mapping — --network=host means the container shares the host
|
||||
# network stack directly. Gitea binds to 0.0.0.0:3000 on the host.
|
||||
|
||||
# All non-secret settings via GITEA__<SECTION>__<KEY> env vars.
|
||||
# These are safe to store in the Nix store.
|
||||
environment = {
|
||||
USER_UID = "1000";
|
||||
USER_GID = "1000";
|
||||
# Tell gitea where to look for the config
|
||||
USER_UID = "1000";
|
||||
USER_GID = "1000";
|
||||
GITEA_CUSTOM = "/data/gitea";
|
||||
|
||||
# [DEFAULT]
|
||||
GITEA____APP_NAME = homeyConfig.organization;
|
||||
GITEA____RUN_MODE = "prod";
|
||||
|
||||
# [repository]
|
||||
GITEA__repository__ROOT = "/data/git/repositories";
|
||||
|
||||
# [server]
|
||||
GITEA__server__APP_DATA_PATH = "/data/gitea";
|
||||
GITEA__server__DOMAIN = "git.${domain}";
|
||||
GITEA__server__HTTP_PORT = toString cfg.port;
|
||||
GITEA__server__ROOT_URL = "https://git.${domain}/";
|
||||
GITEA__server__DISABLE_SSH = "true";
|
||||
GITEA__server__START_SSH_SERVER = "false";
|
||||
GITEA__server__SSH_PORT = "2222";
|
||||
GITEA__server__SSH_LISTEN_PORT = "2222";
|
||||
GITEA__server__LFS_START_SERVER = "true";
|
||||
GITEA__server__OFFLINE_MODE = "false";
|
||||
|
||||
# [lfs]
|
||||
GITEA__lfs__PATH = "/data/git/lfs";
|
||||
|
||||
# [database]
|
||||
GITEA__database__DB_TYPE = "sqlite3";
|
||||
GITEA__database__PATH = "/data/gitea/gitea.db";
|
||||
GITEA__database__LOG_SQL = "false";
|
||||
|
||||
# [indexer]
|
||||
GITEA__indexer__ISSUE_INDEXER_PATH = "/data/gitea/indexers/issues.bleve";
|
||||
|
||||
# [session]
|
||||
GITEA__session__PROVIDER = "file";
|
||||
GITEA__session__PROVIDER_CONFIG = "/data/gitea/sessions";
|
||||
|
||||
# [picture]
|
||||
GITEA__picture__AVATAR_UPLOAD_PATH = "/data/gitea/avatars";
|
||||
GITEA__picture__REPOSITORY_AVATAR_UPLOAD_PATH = "/data/gitea/repo-avatars";
|
||||
GITEA__picture__DISABLE_GRAVATAR = "false";
|
||||
|
||||
# [attachment]
|
||||
GITEA__attachment__PATH = "/data/gitea/attachments";
|
||||
|
||||
# [log]
|
||||
GITEA__log__MODE = "console";
|
||||
GITEA__log__LEVEL = "info";
|
||||
GITEA__log__ROOT_PATH = "/data/gitea/log";
|
||||
|
||||
# [security]
|
||||
GITEA__security__INSTALL_LOCK = "true";
|
||||
GITEA__security__REVERSE_PROXY_LIMIT = "1";
|
||||
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES = "*";
|
||||
|
||||
# [service]
|
||||
GITEA__service__DISABLE_REGISTRATION = "true";
|
||||
GITEA__service__REQUIRE_SIGNIN_VIEW = "false";
|
||||
GITEA__service__REGISTER_EMAIL_CONFIRM = "false";
|
||||
GITEA__service__ENABLE_NOTIFY_MAIL = "false";
|
||||
GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION = "true";
|
||||
GITEA__service__ENABLE_CAPTCHA = "false";
|
||||
GITEA__service__DEFAULT_ALLOW_CREATE_ORGANIZATION = "true";
|
||||
GITEA__service__DEFAULT_ENABLE_TIMETRACKING = "true";
|
||||
GITEA__service__NO_REPLY_ADDRESS = "noreply.localhost";
|
||||
GITEA__service__ENABLE_REVERSE_PROXY_AUTHENTICATION = "true";
|
||||
GITEA__service__ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = "true";
|
||||
|
||||
# [mailer]
|
||||
GITEA__mailer__ENABLED = "false";
|
||||
|
||||
# [openid]
|
||||
GITEA__openid__ENABLE_OPENID_SIGNIN = "false";
|
||||
GITEA__openid__ENABLE_OPENID_SIGNUP = "false";
|
||||
|
||||
# [oauth2]
|
||||
GITEA__oauth2__ENABLED = "false";
|
||||
};
|
||||
|
||||
# Secret env vars written at runtime by ExecStartPre — never in store.
|
||||
environmentFiles = [ "/run/gitea-secrets.env" ];
|
||||
|
||||
volumes = [
|
||||
"${dataDir}/gitea/data:/data"
|
||||
# The processed app.ini is written by ExecStartPre into /run/gitea-conf/
|
||||
"/run/gitea-conf/app.ini:/data/gitea/conf/app.ini:ro"
|
||||
];
|
||||
|
||||
extraOptions = [ "--network=host" ];
|
||||
};
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# ExecStartPre: substitute secret placeholders into the ini template
|
||||
# ExecStartPre: write ephemeral secrets env file
|
||||
# ExecStopPost: clean it up
|
||||
# -----------------------------------------------------------------------
|
||||
systemd.services."podman-gitea" = {
|
||||
serviceConfig = {
|
||||
ExecStartPre = [
|
||||
(pkgs.writeShellScript "gitea-build-config" ''
|
||||
(pkgs.writeShellScript "gitea-write-secrets" ''
|
||||
set -euo pipefail
|
||||
install -d -m 700 /run/gitea-conf
|
||||
LFS=$(cat ${config.sops.secrets."gitea/lfs_jwt_secret".path})
|
||||
OAUTH=$(cat ${config.sops.secrets."gitea/oauth2_jwt_secret".path})
|
||||
TOKEN=$(cat ${config.sops.secrets."gitea/internal_token".path})
|
||||
sed \
|
||||
-e "s|__GITEA_LFS_JWT_SECRET__|$LFS|g" \
|
||||
-e "s|__GITEA_OAUTH2_JWT_SECRET__|$OAUTH|g" \
|
||||
-e "s|__GITEA_INTERNAL_TOKEN__|$TOKEN|g" \
|
||||
/etc/gitea/app.ini.tpl > /run/gitea-conf/app.ini
|
||||
chmod 444 /run/gitea-conf/app.ini
|
||||
printf '%s\n' \
|
||||
"GITEA__server__LFS_JWT_SECRET=$LFS" \
|
||||
"GITEA__security__INTERNAL_TOKEN=$TOKEN" \
|
||||
"GITEA__oauth2__JWT_SECRET=$OAUTH" \
|
||||
> /run/gitea-secrets.env
|
||||
chmod 600 /run/gitea-secrets.env
|
||||
'')
|
||||
];
|
||||
ExecStopPost = [
|
||||
(pkgs.writeShellScript "gitea-cleanup-secrets" ''
|
||||
rm -f /run/gitea-secrets.env
|
||||
'')
|
||||
];
|
||||
};
|
||||
after = lib.mkAfter [ "mnt-data.mount" "podman-openldap.service" ];
|
||||
requires = lib.mkAfter [ "mnt-data.mount" ];
|
||||
after = lib.mkAfter [ "mnt-data.mount" "podman-openldap.service" ];
|
||||
requires = lib.mkAfter [ "mnt-data.mount" ];
|
||||
};
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Ensure the Gitea admin user exists with the correct password after start.
|
||||
# Runs as a oneshot after podman-gitea; idempotent (create or update).
|
||||
# -----------------------------------------------------------------------
|
||||
systemd.services."gitea-admin-setup" = {
|
||||
description = "Ensure Gitea admin user exists with correct password";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "podman-gitea.service" ];
|
||||
requires = [ "podman-gitea.service" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
PASS=$(cat ${config.sops.secrets."gitea/admin_password".path})
|
||||
|
||||
# Wait until Gitea's HTTP endpoint is up (max 60 s)
|
||||
for i in $(seq 1 60); do
|
||||
if ${pkgs.curl}/bin/curl -sf http://127.0.0.1:${toString cfg.port}/ -o /dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Sync password if admin exists; create if not.
|
||||
if ! ${pkgs.podman}/bin/podman exec -u 1000 gitea \
|
||||
gitea admin user change-password --username admin --password "$PASS" 2>/dev/null; then
|
||||
${pkgs.podman}/bin/podman exec -u 1000 gitea \
|
||||
gitea admin user create \
|
||||
--username admin \
|
||||
--password "$PASS" \
|
||||
--email "admin@${domain}" \
|
||||
--admin
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers.jellyfin = {
|
||||
image = cfg.image;
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:8096" ];
|
||||
# No ports mapping — --network=host shares the host network stack directly.
|
||||
|
||||
environment = {
|
||||
JELLYFIN_PublishedServerUrl = "https://jellyfin.${domain}";
|
||||
|
||||
@@ -58,7 +58,7 @@ in
|
||||
# -----------------------------------------------------------------------
|
||||
virtualisation.oci-containers.containers.nextcloud-postgres = {
|
||||
image = cfg.postgresImage;
|
||||
ports = [ "127.0.0.1:${toString cfg.postgresPort}:5432" ];
|
||||
# No ports mapping — --network=host shares the host network stack directly.
|
||||
|
||||
environment = {
|
||||
POSTGRES_DB = "nextcloud_db";
|
||||
@@ -70,20 +70,25 @@ in
|
||||
"${dataDir}/nextcloud/db:/var/lib/postgresql/data"
|
||||
];
|
||||
|
||||
extraOptions = [ "--network=host" ];
|
||||
extraOptions = [
|
||||
"--network=host"
|
||||
"--env-file=/run/nc-postgres-secrets.env"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."podman-nextcloud-postgres" = {
|
||||
serviceConfig = {
|
||||
LoadCredential = [
|
||||
"nextcloud_postgres_password:${config.sops.secrets."nextcloud/postgres_password".path}"
|
||||
];
|
||||
ExecStartPre = [
|
||||
(pkgs.writeShellScript "nc-postgres-secrets-env" ''
|
||||
set -euo pipefail
|
||||
install -m 600 /dev/null /run/nc-postgres-secrets.env
|
||||
echo "POSTGRES_PASSWORD=$(cat ${config.sops.secrets."nextcloud/postgres_password".path})" \
|
||||
echo "POSTGRES_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/nextcloud_postgres_password")" \
|
||||
>> /run/nc-postgres-secrets.env
|
||||
'')
|
||||
];
|
||||
EnvironmentFile = "/run/nc-postgres-secrets.env";
|
||||
};
|
||||
postStop = "rm -f /run/nc-postgres-secrets.env";
|
||||
after = lib.mkAfter [ "mnt-data.mount" ];
|
||||
@@ -95,7 +100,7 @@ in
|
||||
# -----------------------------------------------------------------------
|
||||
virtualisation.oci-containers.containers.nextcloud = {
|
||||
image = cfg.image;
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:80" ];
|
||||
# No ports mapping — --network=host shares the host network stack directly.
|
||||
|
||||
environment = {
|
||||
POSTGRES_HOST = "127.0.0.1";
|
||||
@@ -105,6 +110,10 @@ in
|
||||
NEXTCLOUD_TRUSTED_DOMAINS = "nextcloud.${domain}";
|
||||
OVERWRITEPROTOCOL = "https";
|
||||
OVERWRITECLIURL = "https://nextcloud.${domain}";
|
||||
# With --network=host, port mappings are ignored and the container's
|
||||
# Apache binds directly on the host. Force it onto port 8080 so Caddy
|
||||
# can own 80/443.
|
||||
APACHE_HTTP_PORT_NUMBER = toString cfg.port;
|
||||
# Passwords injected via env file
|
||||
};
|
||||
|
||||
@@ -112,20 +121,26 @@ in
|
||||
"${dataDir}/nextcloud/html:/var/www/html"
|
||||
];
|
||||
|
||||
extraOptions = [ "--network=host" ];
|
||||
extraOptions = [
|
||||
"--network=host"
|
||||
"--env-file=/run/nc-secrets.env"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."podman-nextcloud" = {
|
||||
serviceConfig = {
|
||||
LoadCredential = [
|
||||
"nextcloud_postgres_password:${config.sops.secrets."nextcloud/postgres_password".path}"
|
||||
"nextcloud_admin_password:${config.sops.secrets."nextcloud/admin_password".path}"
|
||||
];
|
||||
ExecStartPre = [
|
||||
(pkgs.writeShellScript "nc-secrets-env" ''
|
||||
set -euo pipefail
|
||||
install -m 600 /dev/null /run/nc-secrets.env
|
||||
echo "POSTGRES_PASSWORD=$(cat ${config.sops.secrets."nextcloud/postgres_password".path})" >> /run/nc-secrets.env
|
||||
echo "NEXTCLOUD_ADMIN_PASSWORD=$(cat ${config.sops.secrets."nextcloud/admin_password".path})" >> /run/nc-secrets.env
|
||||
echo "POSTGRES_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/nextcloud_postgres_password")" >> /run/nc-secrets.env
|
||||
echo "NEXTCLOUD_ADMIN_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/nextcloud_admin_password")" >> /run/nc-secrets.env
|
||||
'')
|
||||
];
|
||||
EnvironmentFile = "/run/nc-secrets.env";
|
||||
};
|
||||
postStop = "rm -f /run/nc-secrets.env";
|
||||
after = lib.mkAfter [ "mnt-data.mount" "podman-nextcloud-postgres.service" ];
|
||||
|
||||
@@ -50,8 +50,10 @@ in
|
||||
virtualisation.oci-containers.containers.openldap = {
|
||||
image = cfg.image;
|
||||
|
||||
# Bind only to localhost — no external exposure
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:389" ];
|
||||
# No ports mapping — --network=host means the container shares the host
|
||||
# network stack. OpenLDAP binds to 0.0.0.0:389, but the firewall
|
||||
# (common.nix) only opens 22/80/443, so port 389 is unreachable from
|
||||
# the LAN or internet.
|
||||
|
||||
environment = {
|
||||
LDAP_ORGANISATION = homeyConfig.organization;
|
||||
@@ -76,8 +78,8 @@ in
|
||||
];
|
||||
|
||||
extraOptions = [
|
||||
"--network=host" # simplest for single-host: services talk on 127.0.0.1
|
||||
"--hostname=openldap"
|
||||
"--network=host"
|
||||
"--env-file=/run/openldap-secrets.env"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -88,18 +90,25 @@ in
|
||||
# podman-<container-name>.service
|
||||
systemd.services."podman-openldap" = {
|
||||
serviceConfig = {
|
||||
# Write an env file with secret values before the container starts,
|
||||
# then pass it to podman run via EnvironmentFile.
|
||||
# LoadCredential stages the sops secrets into a per-invocation
|
||||
# credential directory before any Exec* step, so they are available
|
||||
# when ExecStartPre runs. ExecStartPre writes the env file that
|
||||
# podman --env-file reads; this avoids the EnvironmentFile ordering
|
||||
# race (EnvironmentFile is evaluated before ExecStartPre).
|
||||
LoadCredential = [
|
||||
"openldap_admin_password:${config.sops.secrets."openldap/admin_password".path}"
|
||||
"openldap_config_password:${config.sops.secrets."openldap/config_password".path}"
|
||||
"openldap_ro_password:${config.sops.secrets."openldap/ro_password".path}"
|
||||
];
|
||||
ExecStartPre = [
|
||||
(pkgs.writeShellScript "openldap-secrets-env" ''
|
||||
set -euo pipefail
|
||||
install -m 600 /dev/null /run/openldap-secrets.env
|
||||
echo "LDAP_ADMIN_PASSWORD=$(cat ${config.sops.secrets."openldap/admin_password".path})" >> /run/openldap-secrets.env
|
||||
echo "LDAP_CONFIG_PASSWORD=$(cat ${config.sops.secrets."openldap/config_password".path})" >> /run/openldap-secrets.env
|
||||
echo "LDAP_READONLY_USER_PASSWORD=$(cat ${config.sops.secrets."openldap/ro_password".path})" >> /run/openldap-secrets.env
|
||||
echo "LDAP_ADMIN_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/openldap_admin_password")" >> /run/openldap-secrets.env
|
||||
echo "LDAP_CONFIG_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/openldap_config_password")" >> /run/openldap-secrets.env
|
||||
echo "LDAP_READONLY_USER_PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/openldap_ro_password")" >> /run/openldap-secrets.env
|
||||
'')
|
||||
];
|
||||
EnvironmentFile = "/run/openldap-secrets.env";
|
||||
};
|
||||
# Clean up the env file on stop
|
||||
postStop = "rm -f /run/openldap-secrets.env";
|
||||
@@ -109,8 +118,8 @@ in
|
||||
};
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Firewall — openldap port is NOT opened externally (localhost only)
|
||||
# Firewall — openldap port is NOT opened externally
|
||||
# -----------------------------------------------------------------------
|
||||
# No firewall rule needed; bound to 127.0.0.1.
|
||||
# No firewall rule needed; common.nix only opens 22/80/443.
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
# Stateless container (no persistent volumes needed).
|
||||
# Protected by Authelia two_factor, admins-only policy (defined in authelia.nix).
|
||||
# Bound to localhost:8081; Caddy reverse-proxies it.
|
||||
#
|
||||
# Networking: uses default bridge (podman) network with a port mapping
|
||||
# 127.0.0.1:8081->80 so Caddy can reach it. OpenLDAP runs on the host
|
||||
# network at 127.0.0.1:389; the container reaches it via the special
|
||||
# host.containers.internal DNS name that podman injects automatically.
|
||||
|
||||
let
|
||||
cfg = config.homey.phpldapadmin;
|
||||
@@ -28,14 +33,17 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers.phpldapadmin = {
|
||||
image = cfg.image;
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:80" ];
|
||||
|
||||
environment = {
|
||||
PHPLDAPADMIN_HTTPS = "false";
|
||||
PHPLDAPADMIN_LDAP_HOSTS = "127.0.0.1"; # openldap on host network
|
||||
PHPLDAPADMIN_HTTPS = "false";
|
||||
# host.containers.internal resolves to the host from inside a podman
|
||||
# bridge container — reaches openldap which is on --network=host at :389
|
||||
PHPLDAPADMIN_LDAP_HOSTS = "host.containers.internal";
|
||||
};
|
||||
|
||||
extraOptions = [ "--network=host" ];
|
||||
# Bridge network (default) + port mapping: Apache binds inside the
|
||||
# container on :80, podman maps it to 127.0.0.1:8081 on the host.
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:80" ];
|
||||
};
|
||||
|
||||
systemd.services."podman-phpldapadmin" = {
|
||||
|
||||
@@ -35,11 +35,16 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers.transmission = {
|
||||
image = cfg.image;
|
||||
ports = [ "127.0.0.1:${toString cfg.port}:9091" ];
|
||||
# No ports mapping — --network=host shares the host network stack directly.
|
||||
|
||||
environment = {
|
||||
PUID = "1000";
|
||||
PGID = "1000";
|
||||
# With --network=host, port mappings are ignored; transmission binds
|
||||
# directly on the host. Force it to cfg.port (9092) to avoid
|
||||
# conflicting with Authelia on 9091.
|
||||
TRANSMISSION_WEB_HOME = "/usr/share/transmission/web";
|
||||
WEBUI_PORT = toString cfg.port;
|
||||
};
|
||||
|
||||
volumes = [
|
||||
|
||||
Reference in New Issue
Block a user