mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 10:22:08 +00:00
feat(oci): add Authentik catalog profile
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
<!-- Generated from oci/catalog/verification.json by .github/scripts/oci_validation.py. Do not edit by hand. -->
|
||||
|
||||
44 of 530 applications in the OCI catalog have been tested for real: 41 in the ProxMenux lab and 3 by the community. The OCI installer shows them as verified, with a ✓ in the lists.
|
||||
44 of 531 applications in the OCI catalog have been tested for real: 41 in the ProxMenux lab and 3 by the community. The OCI installer shows them as verified, with a ✓ in the lists.
|
||||
|
||||
Each test describes the scenario that was run and names the image it ran on. It does not cover every possible configuration of the application, and a newer image has not been tested until someone reports it.
|
||||
|
||||
|
||||
@@ -0,0 +1,645 @@
|
||||
{
|
||||
"schema_version": "0.5.0",
|
||||
"kind": "proxmenux.oci-template",
|
||||
"id": "image-authentik",
|
||||
"status": "generated-unvalidated",
|
||||
"catalog_ui": {
|
||||
"title": {
|
||||
"en_US": "Authentik"
|
||||
},
|
||||
"tagline": {
|
||||
"en_US": "Identity provider for single sign-on and access control"
|
||||
},
|
||||
"description": {
|
||||
"en_US": "Authentik is an open-source identity provider and access platform. This recipe follows the official three-service deployment with PostgreSQL, the server and a worker, each in its own Proxmox OCI LXC."
|
||||
},
|
||||
"category": "security",
|
||||
"category_label": "Authentication & Security",
|
||||
"author": "Authentik",
|
||||
"developer": "Authentik",
|
||||
"icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authentik.webp",
|
||||
"thumbnail": null,
|
||||
"screenshots": [],
|
||||
"architectures": [
|
||||
"amd64",
|
||||
"arm64"
|
||||
],
|
||||
"launch": {
|
||||
"scheme": "http",
|
||||
"port": 9000,
|
||||
"path": "/"
|
||||
},
|
||||
"website": "https://goauthentik.io/",
|
||||
"documentation": "https://docs.goauthentik.io/install-config/install/docker-compose/",
|
||||
"repository": "https://github.com/goauthentik/authentik",
|
||||
"tips": [
|
||||
"The server and worker share /data and /templates through host directories; those directories are not included in Proxmox CT backups.",
|
||||
"The worker Docker-socket mount is omitted. Use the embedded outpost or deploy and manage a separate outpost manually."
|
||||
],
|
||||
"mini_changelog": [],
|
||||
"display_version": "2026.8.5",
|
||||
"updated_at": "2026-10-21"
|
||||
},
|
||||
"source": {
|
||||
"provider": "goauthentik",
|
||||
"repository": "https://github.com/goauthentik/authentik",
|
||||
"default_branch": "main",
|
||||
"revision": "4ec0d19b98da3c329781894cd550da95d3033954",
|
||||
"readme_raw_url": "https://goauthentik.io/version/2026.8/lifecycle/container/compose.yml",
|
||||
"image_repository_url": "https://github.com/goauthentik/authentik/pkgs/container/server",
|
||||
"readme_pushed_at": "2026-10-21T12:57:59Z",
|
||||
"compose_sha256": "a3e138b5a85844d15c4a7ba6339997e43c0479d9d198582c67dd19523aadc694",
|
||||
"generated_at": "2026-10-30T18:09:01+00:00"
|
||||
},
|
||||
"container_contract": {
|
||||
"service_name": "server",
|
||||
"container_name": "authentik-server",
|
||||
"image": {
|
||||
"reference": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"registry": "ghcr.io",
|
||||
"repository": "ghcr.io/goauthentik/server",
|
||||
"tag": "2026.8.5",
|
||||
"digest": null,
|
||||
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__HOST",
|
||||
"example": "postgresql",
|
||||
"required": true,
|
||||
"sensitive": false,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__NAME",
|
||||
"example": "authentik",
|
||||
"required": true,
|
||||
"sensitive": false,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__PASSWORD",
|
||||
"example": "${GENERATED_GENERATED_PG_PASS}",
|
||||
"required": true,
|
||||
"sensitive": true,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__USER",
|
||||
"example": "authentik",
|
||||
"required": true,
|
||||
"sensitive": false,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_SECRET_KEY",
|
||||
"example": "${GENERATED_GENERATED_AUTHENTIK_SECRET_KEY}",
|
||||
"required": true,
|
||||
"sensitive": true,
|
||||
"source": "docker-compose"
|
||||
}
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"id": "volume-0",
|
||||
"container_path": "/data",
|
||||
"compose_source_example": "./data",
|
||||
"read_only": false,
|
||||
"required": true,
|
||||
"installation_choice": [
|
||||
"host-bind"
|
||||
],
|
||||
"default": "host-bind",
|
||||
"managed_volume": {
|
||||
"backup": false,
|
||||
"default_size_gb": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "volume-1",
|
||||
"container_path": "/templates",
|
||||
"compose_source_example": "./custom-templates",
|
||||
"read_only": false,
|
||||
"required": true,
|
||||
"installation_choice": [
|
||||
"host-bind"
|
||||
],
|
||||
"default": "host-bind",
|
||||
"managed_volume": {
|
||||
"backup": false,
|
||||
"default_size_gb": 8
|
||||
}
|
||||
}
|
||||
],
|
||||
"ports": [
|
||||
{
|
||||
"container_port": 9000,
|
||||
"published_example": 9000,
|
||||
"protocol": "tcp",
|
||||
"required": true,
|
||||
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
|
||||
},
|
||||
{
|
||||
"container_port": 9443,
|
||||
"published_example": 9443,
|
||||
"protocol": "tcp",
|
||||
"required": true,
|
||||
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
|
||||
}
|
||||
],
|
||||
"related_services": [
|
||||
{
|
||||
"name": "postgresql",
|
||||
"image": "docker.io/library/postgres:16-alpine"
|
||||
},
|
||||
{
|
||||
"name": "worker",
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5"
|
||||
}
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"stop_grace_period": null,
|
||||
"original_compose": "name: authentik\nservices:\n postgresql:\n environment:\n POSTGRES_DB: authentik\n POSTGRES_PASSWORD: ${GENERATED_PG_PASS}\n POSTGRES_USER: authentik\n healthcheck:\n interval: 30s\n retries: 5\n start_period: 20s\n test:\n - CMD-SHELL\n - pg_isready -h 127.0.0.1 -d authentik -U authentik\n timeout: 5s\n image: docker.io/library/postgres:16-alpine\n restart: unless-stopped\n volumes:\n - read_only: false\n source: database\n target: /var/lib/postgresql/data\n server:\n command: server\n depends_on:\n postgresql:\n condition: service_healthy\n environment:\n AUTHENTIK_POSTGRESQL__HOST: postgresql\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${GENERATED_PG_PASS}\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_SECRET_KEY: ${GENERATED_AUTHENTIK_SECRET_KEY}\n image: ghcr.io/goauthentik/server:2026.8.5\n ports:\n - 9000:9000\n - 9443:9443\n restart: unless-stopped\n shm_size: 512mb\n volumes:\n - read_only: false\n source: ./data\n target: /data\n - read_only: false\n source: ./custom-templates\n target: /templates\n worker:\n command: worker\n depends_on:\n postgresql:\n condition: service_healthy\n environment:\n AUTHENTIK_POSTGRESQL__HOST: postgresql\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${GENERATED_PG_PASS}\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_SECRET_KEY: ${GENERATED_AUTHENTIK_SECRET_KEY}\n image: ghcr.io/goauthentik/server:2026.8.5\n restart: unless-stopped\n shm_size: 512mb\n user: root\n volumes:\n - read_only: false\n source: ./data\n target: /data\n - read_only: false\n source: ./certs\n target: /certs\n - read_only: false\n source: ./custom-templates\n target: /templates\nvolumes:\n database: {}\n"
|
||||
},
|
||||
"compose_stack": {
|
||||
"project_name": "authentik",
|
||||
"deployment_model": "one-native-oci-lxc-per-compose-service",
|
||||
"user_experience": "single-application-install",
|
||||
"main_service": "server",
|
||||
"service_count": 3,
|
||||
"services": [
|
||||
{
|
||||
"name": "postgresql",
|
||||
"image": "docker.io/library/postgres:16-alpine",
|
||||
"is_main": false,
|
||||
"role": "dependency",
|
||||
"vmid_offset": 1,
|
||||
"depends_on": [],
|
||||
"frontend_network": false,
|
||||
"private_network": true,
|
||||
"compose": {
|
||||
"environment": {
|
||||
"POSTGRES_DB": "authentik",
|
||||
"POSTGRES_PASSWORD": "${GENERATED_PG_PASS}",
|
||||
"POSTGRES_USER": "authentik"
|
||||
},
|
||||
"healthcheck": {
|
||||
"interval": "30s",
|
||||
"retries": 5,
|
||||
"start_period": "20s",
|
||||
"test": [
|
||||
"CMD-SHELL",
|
||||
"pg_isready -h 127.0.0.1 -d authentik -U authentik"
|
||||
],
|
||||
"timeout": "5s"
|
||||
},
|
||||
"image": "docker.io/library/postgres:16-alpine",
|
||||
"restart": "unless-stopped",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "database",
|
||||
"target": "/var/lib/postgresql/data",
|
||||
"read_only": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "worker",
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"is_main": false,
|
||||
"role": "dependency",
|
||||
"vmid_offset": 2,
|
||||
"depends_on": [
|
||||
"postgresql"
|
||||
],
|
||||
"frontend_network": false,
|
||||
"private_network": true,
|
||||
"compose": {
|
||||
"command": "worker",
|
||||
"depends_on": {
|
||||
"postgresql": {
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"AUTHENTIK_POSTGRESQL__HOST": "postgresql",
|
||||
"AUTHENTIK_POSTGRESQL__NAME": "authentik",
|
||||
"AUTHENTIK_POSTGRESQL__PASSWORD": "${GENERATED_PG_PASS}",
|
||||
"AUTHENTIK_POSTGRESQL__USER": "authentik",
|
||||
"AUTHENTIK_SECRET_KEY": "${GENERATED_AUTHENTIK_SECRET_KEY}"
|
||||
},
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"restart": "unless-stopped",
|
||||
"shm_size": "512mb",
|
||||
"user": "root",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "./data",
|
||||
"target": "/data",
|
||||
"read_only": false
|
||||
},
|
||||
{
|
||||
"source": "./certs",
|
||||
"target": "/certs",
|
||||
"read_only": false
|
||||
},
|
||||
{
|
||||
"source": "./custom-templates",
|
||||
"target": "/templates",
|
||||
"read_only": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server",
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"is_main": true,
|
||||
"role": "frontend",
|
||||
"vmid_offset": 0,
|
||||
"depends_on": [
|
||||
"postgresql"
|
||||
],
|
||||
"frontend_network": true,
|
||||
"private_network": true,
|
||||
"compose": {
|
||||
"command": "server",
|
||||
"depends_on": {
|
||||
"postgresql": {
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"AUTHENTIK_POSTGRESQL__HOST": "postgresql",
|
||||
"AUTHENTIK_POSTGRESQL__NAME": "authentik",
|
||||
"AUTHENTIK_POSTGRESQL__PASSWORD": "${GENERATED_PG_PASS}",
|
||||
"AUTHENTIK_POSTGRESQL__USER": "authentik",
|
||||
"AUTHENTIK_SECRET_KEY": "${GENERATED_AUTHENTIK_SECRET_KEY}"
|
||||
},
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"ports": [
|
||||
"9000:9000",
|
||||
"9443:9443"
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"shm_size": "512mb",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "./data",
|
||||
"target": "/data",
|
||||
"read_only": false
|
||||
},
|
||||
{
|
||||
"source": "./custom-templates",
|
||||
"target": "/templates",
|
||||
"read_only": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"top_level": {
|
||||
"name": "authentik",
|
||||
"volumes": {
|
||||
"database": {}
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"frontend": "selected-proxmox-bridge",
|
||||
"private_required": true,
|
||||
"private_creation": "automatic-create-if-missing",
|
||||
"private_address_allocation": "automatic-static-address-per-service",
|
||||
"service_discovery": "private-addresses-with-compose-service-host-aliases",
|
||||
"dependency_external_access": "disabled-unless-service-publishes-ports",
|
||||
"prompt_user_for_private_network": false
|
||||
},
|
||||
"storage": [
|
||||
{
|
||||
"id": "postgresql-volume-0",
|
||||
"service": "postgresql",
|
||||
"container_path": "/var/lib/postgresql/data",
|
||||
"mode": "managed-volume",
|
||||
"user_selectable": false,
|
||||
"backup": true,
|
||||
"shared_with_other_lxc": false,
|
||||
"source_path": null,
|
||||
"source_path_prompt": null
|
||||
},
|
||||
{
|
||||
"id": "server-volume-0",
|
||||
"service": "server",
|
||||
"container_path": "/data",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/data"
|
||||
},
|
||||
{
|
||||
"id": "server-volume-1",
|
||||
"service": "server",
|
||||
"container_path": "/templates",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/templates"
|
||||
},
|
||||
{
|
||||
"id": "worker-volume-0",
|
||||
"service": "worker",
|
||||
"container_path": "/data",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/data"
|
||||
},
|
||||
{
|
||||
"id": "worker-volume-1",
|
||||
"service": "worker",
|
||||
"container_path": "/certs",
|
||||
"mode": "managed-volume",
|
||||
"user_selectable": false,
|
||||
"backup": true,
|
||||
"shared_with_other_lxc": false,
|
||||
"source_path": null,
|
||||
"source_path_prompt": null
|
||||
},
|
||||
{
|
||||
"id": "worker-volume-2",
|
||||
"service": "worker",
|
||||
"container_path": "/templates",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/templates"
|
||||
}
|
||||
],
|
||||
"orchestration": {
|
||||
"reserve_vmids_atomically": 3,
|
||||
"start_order": [
|
||||
"postgresql",
|
||||
"worker",
|
||||
"server"
|
||||
],
|
||||
"stop_order": [
|
||||
"server",
|
||||
"worker",
|
||||
"postgresql"
|
||||
],
|
||||
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
|
||||
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
|
||||
},
|
||||
"installer_inputs": {
|
||||
"prompted": [
|
||||
"stack_name",
|
||||
"base_vmid",
|
||||
"rootfs_storage",
|
||||
"persistent_data_destinations",
|
||||
"frontend_bridge",
|
||||
"frontend_ipv4_mode"
|
||||
],
|
||||
"automatic": [
|
||||
"dependent_vmids",
|
||||
"private_bridge",
|
||||
"private_subnet",
|
||||
"private_service_addresses",
|
||||
"compose_service_aliases",
|
||||
"generated_secrets",
|
||||
"dependency_start_and_stop_order"
|
||||
],
|
||||
"generated_secrets": [
|
||||
{
|
||||
"id": "pg-pass",
|
||||
"strategy": "generate-cryptographically-random-at-install",
|
||||
"bindings": [
|
||||
{
|
||||
"service": "postgresql",
|
||||
"environment_variable": "POSTGRES_PASSWORD"
|
||||
},
|
||||
{
|
||||
"service": "server",
|
||||
"environment_variable": "AUTHENTIK_POSTGRESQL__PASSWORD"
|
||||
},
|
||||
{
|
||||
"service": "worker",
|
||||
"environment_variable": "AUTHENTIK_POSTGRESQL__PASSWORD"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "authentik-secret-key",
|
||||
"strategy": "generate-cryptographically-random-at-install",
|
||||
"bindings": [
|
||||
{
|
||||
"service": "server",
|
||||
"environment_variable": "AUTHENTIK_SECRET_KEY"
|
||||
},
|
||||
{
|
||||
"service": "worker",
|
||||
"environment_variable": "AUTHENTIK_SECRET_KEY"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"first_run": {
|
||||
"endpoints": [
|
||||
{
|
||||
"label": "Web interface",
|
||||
"scheme": "http",
|
||||
"port": 9000,
|
||||
"path": "/",
|
||||
"source": "official-compose"
|
||||
}
|
||||
],
|
||||
"credentials": [
|
||||
{
|
||||
"label": "Initial administrator account",
|
||||
"type": "static-default",
|
||||
"username": "akadmin",
|
||||
"password": null,
|
||||
"change_required": true,
|
||||
"source": "Authentik documentation; set the akadmin password during the first-run setup"
|
||||
}
|
||||
]
|
||||
},
|
||||
"proxmox": {
|
||||
"runtime": "native-oci-lxc",
|
||||
"technology_status": "proxmox-technology-preview",
|
||||
"defaults": {
|
||||
"unprivileged": true,
|
||||
"ostype": "auto-from-image",
|
||||
"cores": 2,
|
||||
"memory_mb": 1024,
|
||||
"swap_mb": 512,
|
||||
"rootfs_size_gb": 8,
|
||||
"rootfs_storage": "local-lvm",
|
||||
"volume_storage": "local-lvm",
|
||||
"template_storage": "local",
|
||||
"bridge": "vmbr0",
|
||||
"ipv4": "dhcp",
|
||||
"firewall": true,
|
||||
"host_managed_network": true,
|
||||
"onboot": true,
|
||||
"features": [
|
||||
"nesting=1"
|
||||
],
|
||||
"shutdown_timeout_seconds": 30
|
||||
},
|
||||
"image_metadata_policy": {
|
||||
"entrypoint": "import-from-oci-image",
|
||||
"cmd": "import-from-oci-image",
|
||||
"environment": "import-image-env-then-apply-compose-overrides",
|
||||
"user": "import-from-oci-image",
|
||||
"working_dir": "import-from-oci-image",
|
||||
"stop_signal": "import-from-oci-image"
|
||||
},
|
||||
"installer_profile": {
|
||||
"stack_driver": "generic-multi-lxc-stack",
|
||||
"volume_preparations": [
|
||||
{
|
||||
"container_path": "/data",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
},
|
||||
{
|
||||
"container_path": "/templates",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
},
|
||||
{
|
||||
"container_path": "/certs",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
},
|
||||
{
|
||||
"container_path": "/var/lib/postgresql/data",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
}
|
||||
]
|
||||
},
|
||||
"adaptations": [
|
||||
{
|
||||
"id": "worker-docker-socket-removed",
|
||||
"upstream_behavior": "The official Compose mounts the Docker socket into the worker for automatic deployment and management of separate outposts.",
|
||||
"native_lxc_behavior": "The Docker socket mount is omitted. Authentik itself runs as server, PostgreSQL and worker in native OCI LXCs.",
|
||||
"reason": "The ProxMenux native OCI stack does not run Docker Engine or provide a Docker daemon socket.",
|
||||
"behavioral_impact": "Use the embedded outpost for a simple proxy-provider deployment, or deploy and manage an outpost separately.",
|
||||
"validation": "passed-ms03-2026-10-30"
|
||||
},
|
||||
{
|
||||
"id": "postgres-healthcheck-normalized",
|
||||
"upstream_behavior": "The official PostgreSQL healthcheck expands Compose environment variables in its command.",
|
||||
"native_lxc_behavior": "The check uses the recipe’s fixed database and username with pg_isready against localhost.",
|
||||
"reason": "The native stack healthcheck runs in the database LXC and does not evaluate Compose variable interpolation.",
|
||||
"behavioral_impact": "It checks the same local database readiness before dependent services start.",
|
||||
"validation": "passed-ms03-postgresql-readiness-2026-10-30"
|
||||
},
|
||||
{
|
||||
"id": "server-worker-shared-data",
|
||||
"upstream_behavior": "Authentik server and worker both mount /data and /templates from the same Compose source directories.",
|
||||
"native_lxc_behavior": "ProxMenux uses shared host directories for these two paths across the server and worker LXCs.",
|
||||
"reason": "The same data and custom templates must be visible to both services; the stack driver shares named Compose sources through host paths.",
|
||||
"behavioral_impact": "These shared host directories are not included in native LXC backups and need a separate backup.",
|
||||
"validation": "passed-ms03-2026-10-30"
|
||||
}
|
||||
],
|
||||
"custom_compose_stack": true,
|
||||
"custom_compose_interpolated": false,
|
||||
"stack_image_entrypoints": {}
|
||||
},
|
||||
"compatibility": {
|
||||
"automatic_install_candidate": true,
|
||||
"validated": false,
|
||||
"supported_compose_keys": [
|
||||
"cap_add",
|
||||
"command",
|
||||
"container_name",
|
||||
"cpu_shares",
|
||||
"deploy",
|
||||
"devices",
|
||||
"entrypoint",
|
||||
"environment",
|
||||
"extra_hosts",
|
||||
"group_add",
|
||||
"healthcheck",
|
||||
"hostname",
|
||||
"image",
|
||||
"init",
|
||||
"ipc",
|
||||
"labels",
|
||||
"logging",
|
||||
"mac_address",
|
||||
"mem_limit",
|
||||
"network_mode",
|
||||
"networks",
|
||||
"ports",
|
||||
"privileged",
|
||||
"restart",
|
||||
"runtime",
|
||||
"security_opt",
|
||||
"shm_size",
|
||||
"stdin_open",
|
||||
"stop_grace_period",
|
||||
"stop_signal",
|
||||
"sysctls",
|
||||
"tty",
|
||||
"ulimits",
|
||||
"user",
|
||||
"volumes",
|
||||
"working_dir"
|
||||
],
|
||||
"untranslated_blockers": [],
|
||||
"policy": "Official Authentik Compose translated to three native OCI LXCs. The Docker socket mount is deliberately removed; the embedded outpost remains available."
|
||||
},
|
||||
"validation": {
|
||||
"schema": "passed-local-2026-10-30",
|
||||
"image_pull": "passed-ms03-skopeo-and-OCI-integrity-server-worker-postgresql-2026-10-30",
|
||||
"default_install": "passed-ms03-three-LXCs-started-PostgreSQL-healthy-2026-10-30",
|
||||
"advanced_install": "pending",
|
||||
"credentials": "pending-user-first-run-and-login",
|
||||
"web_ui": "pending-user-first-run-and-login",
|
||||
"storage_modes": "pending",
|
||||
"restart_persistence": "pending",
|
||||
"backup_restore": "pending",
|
||||
"update_preserves_data": "pending",
|
||||
"rollback": "pending",
|
||||
"modification": "pending",
|
||||
"removal": "pending",
|
||||
"oci_engine_tests": "pending",
|
||||
"offline_i18n_tests": "pending",
|
||||
"runtime_architecture": "amd64-ms03; Skopeo manifests include amd64-and-arm64",
|
||||
"database_health": "passed-pg_isready-2026-10-30"
|
||||
},
|
||||
"lifecycle": {
|
||||
"update_strategy": "resolve-selected-tag-and-architecture-digest-then-apply-reviewed-native-lxc-update",
|
||||
"registry_state": {
|
||||
"resolved_architecture": null,
|
||||
"resolved_digest": null,
|
||||
"image_version_label": "2026.8.5",
|
||||
"image_created": null
|
||||
},
|
||||
"change_detection": "compare-compose-sha256-and-resolved-image-digest",
|
||||
"automatic_unattended_updates": false,
|
||||
"dependency_lifecycle": {
|
||||
"implementation": "proxmox-hookscript",
|
||||
"trigger": "main-lxc-pre-start",
|
||||
"waits_for_dependency_healthchecks": true,
|
||||
"stops_dependencies_with_main": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,645 @@
|
||||
{
|
||||
"schema_version": "0.5.0",
|
||||
"kind": "proxmenux.oci-template",
|
||||
"id": "image-authentik",
|
||||
"status": "generated-unvalidated",
|
||||
"catalog_ui": {
|
||||
"title": {
|
||||
"en_US": "Authentik"
|
||||
},
|
||||
"tagline": {
|
||||
"en_US": "Identity provider for single sign-on and access control"
|
||||
},
|
||||
"description": {
|
||||
"en_US": "Authentik is an open-source identity provider and access platform. This recipe follows the official three-service deployment with PostgreSQL, the server and a worker, each in its own Proxmox OCI LXC."
|
||||
},
|
||||
"category": "security",
|
||||
"category_label": "Authentication & Security",
|
||||
"author": "Authentik",
|
||||
"developer": "Authentik",
|
||||
"icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authentik.webp",
|
||||
"thumbnail": null,
|
||||
"screenshots": [],
|
||||
"architectures": [
|
||||
"amd64",
|
||||
"arm64"
|
||||
],
|
||||
"launch": {
|
||||
"scheme": "http",
|
||||
"port": 9000,
|
||||
"path": "/"
|
||||
},
|
||||
"website": "https://goauthentik.io/",
|
||||
"documentation": "https://docs.goauthentik.io/install-config/install/docker-compose/",
|
||||
"repository": "https://github.com/goauthentik/authentik",
|
||||
"tips": [
|
||||
"The server and worker share /data and /templates through host directories; those directories are not included in Proxmox CT backups.",
|
||||
"The worker Docker-socket mount is omitted. Use the embedded outpost or deploy and manage a separate outpost manually."
|
||||
],
|
||||
"mini_changelog": [],
|
||||
"display_version": "2026.8.5",
|
||||
"updated_at": "2026-10-21"
|
||||
},
|
||||
"source": {
|
||||
"provider": "goauthentik",
|
||||
"repository": "https://github.com/goauthentik/authentik",
|
||||
"default_branch": "main",
|
||||
"revision": "4ec0d19b98da3c329781894cd550da95d3033954",
|
||||
"readme_raw_url": "https://goauthentik.io/version/2026.8/lifecycle/container/compose.yml",
|
||||
"image_repository_url": "https://github.com/goauthentik/authentik/pkgs/container/server",
|
||||
"readme_pushed_at": "2026-10-21T12:57:59Z",
|
||||
"compose_sha256": "a3e138b5a85844d15c4a7ba6339997e43c0479d9d198582c67dd19523aadc694",
|
||||
"generated_at": "2026-10-30T18:09:01+00:00"
|
||||
},
|
||||
"container_contract": {
|
||||
"service_name": "server",
|
||||
"container_name": "authentik-server",
|
||||
"image": {
|
||||
"reference": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"registry": "ghcr.io",
|
||||
"repository": "ghcr.io/goauthentik/server",
|
||||
"tag": "2026.8.5",
|
||||
"digest": null,
|
||||
"pull_policy": "resolve-written-reference-to-architecture-digest-at-install"
|
||||
},
|
||||
"environment": [
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__HOST",
|
||||
"example": "postgresql",
|
||||
"required": true,
|
||||
"sensitive": false,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__NAME",
|
||||
"example": "authentik",
|
||||
"required": true,
|
||||
"sensitive": false,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__PASSWORD",
|
||||
"example": "${GENERATED_GENERATED_PG_PASS}",
|
||||
"required": true,
|
||||
"sensitive": true,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_POSTGRESQL__USER",
|
||||
"example": "authentik",
|
||||
"required": true,
|
||||
"sensitive": false,
|
||||
"source": "docker-compose"
|
||||
},
|
||||
{
|
||||
"name": "AUTHENTIK_SECRET_KEY",
|
||||
"example": "${GENERATED_GENERATED_AUTHENTIK_SECRET_KEY}",
|
||||
"required": true,
|
||||
"sensitive": true,
|
||||
"source": "docker-compose"
|
||||
}
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"id": "volume-0",
|
||||
"container_path": "/data",
|
||||
"compose_source_example": "./data",
|
||||
"read_only": false,
|
||||
"required": true,
|
||||
"installation_choice": [
|
||||
"host-bind"
|
||||
],
|
||||
"default": "host-bind",
|
||||
"managed_volume": {
|
||||
"backup": false,
|
||||
"default_size_gb": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "volume-1",
|
||||
"container_path": "/templates",
|
||||
"compose_source_example": "./custom-templates",
|
||||
"read_only": false,
|
||||
"required": true,
|
||||
"installation_choice": [
|
||||
"host-bind"
|
||||
],
|
||||
"default": "host-bind",
|
||||
"managed_volume": {
|
||||
"backup": false,
|
||||
"default_size_gb": 8
|
||||
}
|
||||
}
|
||||
],
|
||||
"ports": [
|
||||
{
|
||||
"container_port": 9000,
|
||||
"published_example": 9000,
|
||||
"protocol": "tcp",
|
||||
"required": true,
|
||||
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
|
||||
},
|
||||
{
|
||||
"container_port": 9443,
|
||||
"published_example": 9443,
|
||||
"protocol": "tcp",
|
||||
"required": true,
|
||||
"proxmox_behavior": "listener-on-dedicated-lxc-address-no-nat"
|
||||
}
|
||||
],
|
||||
"related_services": [
|
||||
{
|
||||
"name": "postgresql",
|
||||
"image": "docker.io/library/postgres:16-alpine"
|
||||
},
|
||||
{
|
||||
"name": "worker",
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5"
|
||||
}
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"stop_grace_period": null,
|
||||
"original_compose": "name: authentik\nservices:\n postgresql:\n environment:\n POSTGRES_DB: authentik\n POSTGRES_PASSWORD: ${GENERATED_PG_PASS}\n POSTGRES_USER: authentik\n healthcheck:\n interval: 30s\n retries: 5\n start_period: 20s\n test:\n - CMD-SHELL\n - pg_isready -h 127.0.0.1 -d authentik -U authentik\n timeout: 5s\n image: docker.io/library/postgres:16-alpine\n restart: unless-stopped\n volumes:\n - read_only: false\n source: database\n target: /var/lib/postgresql/data\n server:\n command: server\n depends_on:\n postgresql:\n condition: service_healthy\n environment:\n AUTHENTIK_POSTGRESQL__HOST: postgresql\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${GENERATED_PG_PASS}\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_SECRET_KEY: ${GENERATED_AUTHENTIK_SECRET_KEY}\n image: ghcr.io/goauthentik/server:2026.8.5\n ports:\n - 9000:9000\n - 9443:9443\n restart: unless-stopped\n shm_size: 512mb\n volumes:\n - read_only: false\n source: ./data\n target: /data\n - read_only: false\n source: ./custom-templates\n target: /templates\n worker:\n command: worker\n depends_on:\n postgresql:\n condition: service_healthy\n environment:\n AUTHENTIK_POSTGRESQL__HOST: postgresql\n AUTHENTIK_POSTGRESQL__NAME: authentik\n AUTHENTIK_POSTGRESQL__PASSWORD: ${GENERATED_PG_PASS}\n AUTHENTIK_POSTGRESQL__USER: authentik\n AUTHENTIK_SECRET_KEY: ${GENERATED_AUTHENTIK_SECRET_KEY}\n image: ghcr.io/goauthentik/server:2026.8.5\n restart: unless-stopped\n shm_size: 512mb\n user: root\n volumes:\n - read_only: false\n source: ./data\n target: /data\n - read_only: false\n source: ./certs\n target: /certs\n - read_only: false\n source: ./custom-templates\n target: /templates\nvolumes:\n database: {}\n"
|
||||
},
|
||||
"compose_stack": {
|
||||
"project_name": "authentik",
|
||||
"deployment_model": "one-native-oci-lxc-per-compose-service",
|
||||
"user_experience": "single-application-install",
|
||||
"main_service": "server",
|
||||
"service_count": 3,
|
||||
"services": [
|
||||
{
|
||||
"name": "postgresql",
|
||||
"image": "docker.io/library/postgres:16-alpine",
|
||||
"is_main": false,
|
||||
"role": "dependency",
|
||||
"vmid_offset": 1,
|
||||
"depends_on": [],
|
||||
"frontend_network": false,
|
||||
"private_network": true,
|
||||
"compose": {
|
||||
"environment": {
|
||||
"POSTGRES_DB": "authentik",
|
||||
"POSTGRES_PASSWORD": "${GENERATED_PG_PASS}",
|
||||
"POSTGRES_USER": "authentik"
|
||||
},
|
||||
"healthcheck": {
|
||||
"interval": "30s",
|
||||
"retries": 5,
|
||||
"start_period": "20s",
|
||||
"test": [
|
||||
"CMD-SHELL",
|
||||
"pg_isready -h 127.0.0.1 -d authentik -U authentik"
|
||||
],
|
||||
"timeout": "5s"
|
||||
},
|
||||
"image": "docker.io/library/postgres:16-alpine",
|
||||
"restart": "unless-stopped",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "database",
|
||||
"target": "/var/lib/postgresql/data",
|
||||
"read_only": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "worker",
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"is_main": false,
|
||||
"role": "dependency",
|
||||
"vmid_offset": 2,
|
||||
"depends_on": [
|
||||
"postgresql"
|
||||
],
|
||||
"frontend_network": false,
|
||||
"private_network": true,
|
||||
"compose": {
|
||||
"command": "worker",
|
||||
"depends_on": {
|
||||
"postgresql": {
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"AUTHENTIK_POSTGRESQL__HOST": "postgresql",
|
||||
"AUTHENTIK_POSTGRESQL__NAME": "authentik",
|
||||
"AUTHENTIK_POSTGRESQL__PASSWORD": "${GENERATED_PG_PASS}",
|
||||
"AUTHENTIK_POSTGRESQL__USER": "authentik",
|
||||
"AUTHENTIK_SECRET_KEY": "${GENERATED_AUTHENTIK_SECRET_KEY}"
|
||||
},
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"restart": "unless-stopped",
|
||||
"shm_size": "512mb",
|
||||
"user": "root",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "./data",
|
||||
"target": "/data",
|
||||
"read_only": false
|
||||
},
|
||||
{
|
||||
"source": "./certs",
|
||||
"target": "/certs",
|
||||
"read_only": false
|
||||
},
|
||||
{
|
||||
"source": "./custom-templates",
|
||||
"target": "/templates",
|
||||
"read_only": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "server",
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"is_main": true,
|
||||
"role": "frontend",
|
||||
"vmid_offset": 0,
|
||||
"depends_on": [
|
||||
"postgresql"
|
||||
],
|
||||
"frontend_network": true,
|
||||
"private_network": true,
|
||||
"compose": {
|
||||
"command": "server",
|
||||
"depends_on": {
|
||||
"postgresql": {
|
||||
"condition": "service_healthy"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"AUTHENTIK_POSTGRESQL__HOST": "postgresql",
|
||||
"AUTHENTIK_POSTGRESQL__NAME": "authentik",
|
||||
"AUTHENTIK_POSTGRESQL__PASSWORD": "${GENERATED_PG_PASS}",
|
||||
"AUTHENTIK_POSTGRESQL__USER": "authentik",
|
||||
"AUTHENTIK_SECRET_KEY": "${GENERATED_AUTHENTIK_SECRET_KEY}"
|
||||
},
|
||||
"image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"ports": [
|
||||
"9000:9000",
|
||||
"9443:9443"
|
||||
],
|
||||
"restart": "unless-stopped",
|
||||
"shm_size": "512mb",
|
||||
"volumes": [
|
||||
{
|
||||
"source": "./data",
|
||||
"target": "/data",
|
||||
"read_only": false
|
||||
},
|
||||
{
|
||||
"source": "./custom-templates",
|
||||
"target": "/templates",
|
||||
"read_only": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"top_level": {
|
||||
"name": "authentik",
|
||||
"volumes": {
|
||||
"database": {}
|
||||
}
|
||||
},
|
||||
"networking": {
|
||||
"frontend": "selected-proxmox-bridge",
|
||||
"private_required": true,
|
||||
"private_creation": "automatic-create-if-missing",
|
||||
"private_address_allocation": "automatic-static-address-per-service",
|
||||
"service_discovery": "private-addresses-with-compose-service-host-aliases",
|
||||
"dependency_external_access": "disabled-unless-service-publishes-ports",
|
||||
"prompt_user_for_private_network": false
|
||||
},
|
||||
"storage": [
|
||||
{
|
||||
"id": "postgresql-volume-0",
|
||||
"service": "postgresql",
|
||||
"container_path": "/var/lib/postgresql/data",
|
||||
"mode": "managed-volume",
|
||||
"user_selectable": false,
|
||||
"backup": true,
|
||||
"shared_with_other_lxc": false,
|
||||
"source_path": null,
|
||||
"source_path_prompt": null
|
||||
},
|
||||
{
|
||||
"id": "server-volume-0",
|
||||
"service": "server",
|
||||
"container_path": "/data",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/data"
|
||||
},
|
||||
{
|
||||
"id": "server-volume-1",
|
||||
"service": "server",
|
||||
"container_path": "/templates",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/templates"
|
||||
},
|
||||
{
|
||||
"id": "worker-volume-0",
|
||||
"service": "worker",
|
||||
"container_path": "/data",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/data"
|
||||
},
|
||||
{
|
||||
"id": "worker-volume-1",
|
||||
"service": "worker",
|
||||
"container_path": "/certs",
|
||||
"mode": "managed-volume",
|
||||
"user_selectable": false,
|
||||
"backup": true,
|
||||
"shared_with_other_lxc": false,
|
||||
"source_path": null,
|
||||
"source_path_prompt": null
|
||||
},
|
||||
{
|
||||
"id": "worker-volume-2",
|
||||
"service": "worker",
|
||||
"container_path": "/templates",
|
||||
"mode": "host-bind",
|
||||
"user_selectable": true,
|
||||
"backup": false,
|
||||
"shared_with_other_lxc": true,
|
||||
"source_path": null,
|
||||
"source_path_prompt": "Host directory for authentik:/templates"
|
||||
}
|
||||
],
|
||||
"orchestration": {
|
||||
"reserve_vmids_atomically": 3,
|
||||
"start_order": [
|
||||
"postgresql",
|
||||
"worker",
|
||||
"server"
|
||||
],
|
||||
"stop_order": [
|
||||
"server",
|
||||
"worker",
|
||||
"postgresql"
|
||||
],
|
||||
"dependency_readiness": "compose-healthcheck-then-port-or-process-fallback",
|
||||
"rollback_on_failure": "remove-new-rootfs-preserve-created-persistent-volumes"
|
||||
},
|
||||
"installer_inputs": {
|
||||
"prompted": [
|
||||
"stack_name",
|
||||
"base_vmid",
|
||||
"rootfs_storage",
|
||||
"persistent_data_destinations",
|
||||
"frontend_bridge",
|
||||
"frontend_ipv4_mode"
|
||||
],
|
||||
"automatic": [
|
||||
"dependent_vmids",
|
||||
"private_bridge",
|
||||
"private_subnet",
|
||||
"private_service_addresses",
|
||||
"compose_service_aliases",
|
||||
"generated_secrets",
|
||||
"dependency_start_and_stop_order"
|
||||
],
|
||||
"generated_secrets": [
|
||||
{
|
||||
"id": "pg-pass",
|
||||
"strategy": "generate-cryptographically-random-at-install",
|
||||
"bindings": [
|
||||
{
|
||||
"service": "postgresql",
|
||||
"environment_variable": "POSTGRES_PASSWORD"
|
||||
},
|
||||
{
|
||||
"service": "server",
|
||||
"environment_variable": "AUTHENTIK_POSTGRESQL__PASSWORD"
|
||||
},
|
||||
{
|
||||
"service": "worker",
|
||||
"environment_variable": "AUTHENTIK_POSTGRESQL__PASSWORD"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "authentik-secret-key",
|
||||
"strategy": "generate-cryptographically-random-at-install",
|
||||
"bindings": [
|
||||
{
|
||||
"service": "server",
|
||||
"environment_variable": "AUTHENTIK_SECRET_KEY"
|
||||
},
|
||||
{
|
||||
"service": "worker",
|
||||
"environment_variable": "AUTHENTIK_SECRET_KEY"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"first_run": {
|
||||
"endpoints": [
|
||||
{
|
||||
"label": "Web interface",
|
||||
"scheme": "http",
|
||||
"port": 9000,
|
||||
"path": "/",
|
||||
"source": "official-compose"
|
||||
}
|
||||
],
|
||||
"credentials": [
|
||||
{
|
||||
"label": "Initial administrator account",
|
||||
"type": "static-default",
|
||||
"username": "akadmin",
|
||||
"password": null,
|
||||
"change_required": true,
|
||||
"source": "Authentik documentation; set the akadmin password during the first-run setup"
|
||||
}
|
||||
]
|
||||
},
|
||||
"proxmox": {
|
||||
"runtime": "native-oci-lxc",
|
||||
"technology_status": "proxmox-technology-preview",
|
||||
"defaults": {
|
||||
"unprivileged": true,
|
||||
"ostype": "auto-from-image",
|
||||
"cores": 2,
|
||||
"memory_mb": 1024,
|
||||
"swap_mb": 512,
|
||||
"rootfs_size_gb": 8,
|
||||
"rootfs_storage": "local-lvm",
|
||||
"volume_storage": "local-lvm",
|
||||
"template_storage": "local",
|
||||
"bridge": "vmbr0",
|
||||
"ipv4": "dhcp",
|
||||
"firewall": true,
|
||||
"host_managed_network": true,
|
||||
"onboot": true,
|
||||
"features": [
|
||||
"nesting=1"
|
||||
],
|
||||
"shutdown_timeout_seconds": 30
|
||||
},
|
||||
"image_metadata_policy": {
|
||||
"entrypoint": "import-from-oci-image",
|
||||
"cmd": "import-from-oci-image",
|
||||
"environment": "import-image-env-then-apply-compose-overrides",
|
||||
"user": "import-from-oci-image",
|
||||
"working_dir": "import-from-oci-image",
|
||||
"stop_signal": "import-from-oci-image"
|
||||
},
|
||||
"installer_profile": {
|
||||
"stack_driver": "generic-multi-lxc-stack",
|
||||
"volume_preparations": [
|
||||
{
|
||||
"container_path": "/data",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
},
|
||||
{
|
||||
"container_path": "/templates",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
},
|
||||
{
|
||||
"container_path": "/certs",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
},
|
||||
{
|
||||
"container_path": "/var/lib/postgresql/data",
|
||||
"remove_lost_found": true,
|
||||
"owner_strategy": "mapped-application-user",
|
||||
"only_when_mount_type": "managed-volume"
|
||||
}
|
||||
]
|
||||
},
|
||||
"adaptations": [
|
||||
{
|
||||
"id": "worker-docker-socket-removed",
|
||||
"upstream_behavior": "The official Compose mounts the Docker socket into the worker for automatic deployment and management of separate outposts.",
|
||||
"native_lxc_behavior": "The Docker socket mount is omitted. Authentik itself runs as server, PostgreSQL and worker in native OCI LXCs.",
|
||||
"reason": "The ProxMenux native OCI stack does not run Docker Engine or provide a Docker daemon socket.",
|
||||
"behavioral_impact": "Use the embedded outpost for a simple proxy-provider deployment, or deploy and manage an outpost separately.",
|
||||
"validation": "passed-ms03-2026-10-30"
|
||||
},
|
||||
{
|
||||
"id": "postgres-healthcheck-normalized",
|
||||
"upstream_behavior": "The official PostgreSQL healthcheck expands Compose environment variables in its command.",
|
||||
"native_lxc_behavior": "The check uses the recipe’s fixed database and username with pg_isready against localhost.",
|
||||
"reason": "The native stack healthcheck runs in the database LXC and does not evaluate Compose variable interpolation.",
|
||||
"behavioral_impact": "It checks the same local database readiness before dependent services start.",
|
||||
"validation": "passed-ms03-postgresql-readiness-2026-10-30"
|
||||
},
|
||||
{
|
||||
"id": "server-worker-shared-data",
|
||||
"upstream_behavior": "Authentik server and worker both mount /data and /templates from the same Compose source directories.",
|
||||
"native_lxc_behavior": "ProxMenux uses shared host directories for these two paths across the server and worker LXCs.",
|
||||
"reason": "The same data and custom templates must be visible to both services; the stack driver shares named Compose sources through host paths.",
|
||||
"behavioral_impact": "These shared host directories are not included in native LXC backups and need a separate backup.",
|
||||
"validation": "passed-ms03-2026-10-30"
|
||||
}
|
||||
],
|
||||
"custom_compose_stack": true,
|
||||
"custom_compose_interpolated": false,
|
||||
"stack_image_entrypoints": {}
|
||||
},
|
||||
"compatibility": {
|
||||
"automatic_install_candidate": true,
|
||||
"validated": false,
|
||||
"supported_compose_keys": [
|
||||
"cap_add",
|
||||
"command",
|
||||
"container_name",
|
||||
"cpu_shares",
|
||||
"deploy",
|
||||
"devices",
|
||||
"entrypoint",
|
||||
"environment",
|
||||
"extra_hosts",
|
||||
"group_add",
|
||||
"healthcheck",
|
||||
"hostname",
|
||||
"image",
|
||||
"init",
|
||||
"ipc",
|
||||
"labels",
|
||||
"logging",
|
||||
"mac_address",
|
||||
"mem_limit",
|
||||
"network_mode",
|
||||
"networks",
|
||||
"ports",
|
||||
"privileged",
|
||||
"restart",
|
||||
"runtime",
|
||||
"security_opt",
|
||||
"shm_size",
|
||||
"stdin_open",
|
||||
"stop_grace_period",
|
||||
"stop_signal",
|
||||
"sysctls",
|
||||
"tty",
|
||||
"ulimits",
|
||||
"user",
|
||||
"volumes",
|
||||
"working_dir"
|
||||
],
|
||||
"untranslated_blockers": [],
|
||||
"policy": "Official Authentik Compose translated to three native OCI LXCs. The Docker socket mount is deliberately removed; the embedded outpost remains available."
|
||||
},
|
||||
"validation": {
|
||||
"schema": "passed-local-2026-10-30",
|
||||
"image_pull": "passed-ms03-skopeo-and-OCI-integrity-server-worker-postgresql-2026-10-30",
|
||||
"default_install": "passed-ms03-three-LXCs-started-PostgreSQL-healthy-2026-10-30",
|
||||
"advanced_install": "pending",
|
||||
"credentials": "pending-user-first-run-and-login",
|
||||
"web_ui": "pending-user-first-run-and-login",
|
||||
"storage_modes": "pending",
|
||||
"restart_persistence": "pending",
|
||||
"backup_restore": "pending",
|
||||
"update_preserves_data": "pending",
|
||||
"rollback": "pending",
|
||||
"modification": "pending",
|
||||
"removal": "pending",
|
||||
"oci_engine_tests": "pending",
|
||||
"offline_i18n_tests": "pending",
|
||||
"runtime_architecture": "amd64-ms03; Skopeo manifests include amd64-and-arm64",
|
||||
"database_health": "passed-pg_isready-2026-10-30"
|
||||
},
|
||||
"lifecycle": {
|
||||
"update_strategy": "resolve-selected-tag-and-architecture-digest-then-apply-reviewed-native-lxc-update",
|
||||
"registry_state": {
|
||||
"resolved_architecture": null,
|
||||
"resolved_digest": null,
|
||||
"image_version_label": "2026.8.5",
|
||||
"image_created": null
|
||||
},
|
||||
"change_detection": "compare-compose-sha256-and-resolved-image-digest",
|
||||
"automatic_unattended_updates": false,
|
||||
"dependency_lifecycle": {
|
||||
"implementation": "proxmox-hookscript",
|
||||
"trigger": "main-lxc-pre-start",
|
||||
"waits_for_dependency_healthchecks": true,
|
||||
"stops_dependencies_with_main": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
-2
@@ -2,7 +2,7 @@
|
||||
"schema_version": "0.2.0",
|
||||
"kind": "proxmenux.oci-catalog-index",
|
||||
"provider": "multiple-container-images",
|
||||
"generated_at": "2026-10-26T08:05:54+00:00",
|
||||
"generated_at": "2026-10-30T18:13:36+00:00",
|
||||
"applications": [
|
||||
{
|
||||
"id": "2fauth",
|
||||
@@ -752,6 +752,39 @@
|
||||
"hidden": false,
|
||||
"template_id": "image-audiobookshelf"
|
||||
},
|
||||
{
|
||||
"id": "authentik",
|
||||
"provider": "goauthentik",
|
||||
"template_family": "curated-profile",
|
||||
"title": "Authentik",
|
||||
"repository": "https://github.com/goauthentik/authentik",
|
||||
"description": "Authentik is an open-source identity provider and access platform. This recipe follows the official three-service deployment with PostgreSQL, the server and a worker, each in its own Proxmox OCI LXC.",
|
||||
"website": "https://goauthentik.io/",
|
||||
"icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/authentik.webp",
|
||||
"architectures": [
|
||||
"amd64",
|
||||
"arm64"
|
||||
],
|
||||
"updated_at": "2026-10-21",
|
||||
"main_image": "ghcr.io/goauthentik/server:2026.8.5",
|
||||
"category": "security",
|
||||
"category_label": "Authentication & Security",
|
||||
"replaces_discovered_ids": [],
|
||||
"curated_path": "catalog/curated/authentik.json",
|
||||
"template_id": "image-authentik",
|
||||
"template": "apps/authentik.json",
|
||||
"template_status": "generated-unvalidated",
|
||||
"hidden": false,
|
||||
"automatic_install_candidate": true,
|
||||
"untranslated_blockers": [],
|
||||
"requires_privileged_lxc": false,
|
||||
"optional_privileged_lxc": false,
|
||||
"requires_host_pid_namespace": false,
|
||||
"requires_relaxed_confinement": false,
|
||||
"optional_relaxed_confinement": false,
|
||||
"requires_security_confirmation": false,
|
||||
"multi_container": true
|
||||
},
|
||||
{
|
||||
"id": "autobrr",
|
||||
"source_app_id": "autobrr",
|
||||
@@ -18976,7 +19009,7 @@
|
||||
"skipped": []
|
||||
},
|
||||
"curated_profiles": {
|
||||
"included_count": 17
|
||||
"included_count": 18
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
"""Authentik keeps the vendor's three-service deployment as native OCI LXCs."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class AuthentikRecipeTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.curated = json.loads(
|
||||
(ROOT / "catalog/curated/authentik.json").read_text(encoding="utf-8")
|
||||
)
|
||||
self.generated = json.loads(
|
||||
(ROOT / "catalog/apps/authentik.json").read_text(encoding="utf-8")
|
||||
)
|
||||
self.services = {
|
||||
service["name"]: service
|
||||
for service in self.curated["compose_stack"]["services"]
|
||||
}
|
||||
|
||||
def test_generated_catalog_copy_matches_curated_profile(self):
|
||||
self.assertEqual(self.curated, self.generated)
|
||||
|
||||
def test_official_three_service_stack_uses_pinned_images_and_order(self):
|
||||
self.assertEqual(set(self.services), {"postgresql", "server", "worker"})
|
||||
self.assertEqual(self.curated["compose_stack"]["main_service"], "server")
|
||||
self.assertEqual(
|
||||
self.services["server"]["image"], "ghcr.io/goauthentik/server:2026.8.5"
|
||||
)
|
||||
self.assertEqual(
|
||||
self.services["worker"]["image"], "ghcr.io/goauthentik/server:2026.8.5"
|
||||
)
|
||||
self.assertEqual(
|
||||
self.services["postgresql"]["image"],
|
||||
"docker.io/library/postgres:16-alpine",
|
||||
)
|
||||
self.assertEqual(self.services["server"]["depends_on"], ["postgresql"])
|
||||
self.assertEqual(self.services["worker"]["depends_on"], ["postgresql"])
|
||||
|
||||
def test_generated_database_and_application_secrets_are_shared_correctly(self):
|
||||
services = {
|
||||
name: service["compose"].get("environment", {})
|
||||
for name, service in self.services.items()
|
||||
}
|
||||
self.assertEqual(
|
||||
services["postgresql"]["POSTGRES_PASSWORD"], "${GENERATED_PG_PASS}"
|
||||
)
|
||||
for name in ("server", "worker"):
|
||||
self.assertEqual(
|
||||
services[name]["AUTHENTIK_POSTGRESQL__PASSWORD"],
|
||||
"${GENERATED_PG_PASS}",
|
||||
)
|
||||
self.assertEqual(
|
||||
services[name]["AUTHENTIK_SECRET_KEY"],
|
||||
"${GENERATED_AUTHENTIK_SECRET_KEY}",
|
||||
)
|
||||
generated = self.curated["compose_stack"]["installer_inputs"][
|
||||
"generated_secrets"
|
||||
]
|
||||
self.assertEqual({secret["id"] for secret in generated}, {
|
||||
"pg-pass",
|
||||
"authentik-secret-key",
|
||||
})
|
||||
|
||||
def test_persistent_mounts_and_database_healthcheck_are_preserved(self):
|
||||
mounts = {
|
||||
name: service["compose"].get("volumes", [])
|
||||
for name, service in self.services.items()
|
||||
}
|
||||
self.assertIn(
|
||||
{"source": "database", "target": "/var/lib/postgresql/data", "read_only": False},
|
||||
mounts["postgresql"],
|
||||
)
|
||||
self.assertIn(
|
||||
{"source": "./data", "target": "/data", "read_only": False},
|
||||
mounts["server"],
|
||||
)
|
||||
self.assertIn(
|
||||
{"source": "./data", "target": "/data", "read_only": False},
|
||||
mounts["worker"],
|
||||
)
|
||||
self.assertIn(
|
||||
{"source": "./custom-templates", "target": "/templates", "read_only": False},
|
||||
mounts["server"],
|
||||
)
|
||||
self.assertIn(
|
||||
{"source": "./custom-templates", "target": "/templates", "read_only": False},
|
||||
mounts["worker"],
|
||||
)
|
||||
self.assertIn(
|
||||
{"source": "./certs", "target": "/certs", "read_only": False},
|
||||
mounts["worker"],
|
||||
)
|
||||
check = self.services["postgresql"]["compose"]["healthcheck"]["test"]
|
||||
self.assertEqual(
|
||||
check,
|
||||
["CMD-SHELL", "pg_isready -h 127.0.0.1 -d authentik -U authentik"],
|
||||
)
|
||||
|
||||
def test_cross_lxc_data_and_templates_are_host_shared_and_backed_up_separately(self):
|
||||
shared = [
|
||||
item
|
||||
for item in self.curated["compose_stack"]["storage"]
|
||||
if item["container_path"] in ("/data", "/templates")
|
||||
]
|
||||
self.assertEqual(len(shared), 4)
|
||||
self.assertTrue(all(item["mode"] == "host-bind" for item in shared))
|
||||
self.assertTrue(all(item["shared_with_other_lxc"] for item in shared))
|
||||
self.assertTrue(all(item["backup"] is False for item in shared))
|
||||
self.assertTrue(
|
||||
all(
|
||||
volume["default"] == "host-bind"
|
||||
and volume["managed_volume"]["backup"] is False
|
||||
for volume in self.curated["container_contract"]["volumes"]
|
||||
)
|
||||
)
|
||||
|
||||
def test_docker_socket_is_not_mounted_and_both_web_ports_are_exposed(self):
|
||||
all_mounts = [
|
||||
mount
|
||||
for service in self.services.values()
|
||||
for mount in service["compose"].get("volumes", [])
|
||||
]
|
||||
self.assertFalse(any("docker.sock" in mount for mount in all_mounts))
|
||||
self.assertEqual(
|
||||
self.services["server"]["compose"]["ports"],
|
||||
["9000:9000", "9443:9443"],
|
||||
)
|
||||
|
||||
def test_first_run_discloses_the_initial_admin_setup_without_faking_a_password(self):
|
||||
first_run = self.curated["first_run"]
|
||||
self.assertEqual(first_run["endpoints"][0]["port"], 9000)
|
||||
credential = first_run["credentials"][0]
|
||||
self.assertEqual(credential["username"], "akadmin")
|
||||
self.assertIsNone(credential["password"])
|
||||
self.assertTrue(credential["change_required"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user