Skip to content

Systemd Ansible Deployment

ContextUnity defines a 100% native systemd deployment pipeline managed neutrally and idempotently via Ansible configuration management. Docker is strictly deprecated for operational service runtimes inside production deployments, ensuring that your host recovers robustly and performs bare-metal speed native memory management.

Declarative Pipeline

  1. Host Environment Prep: The infrastructure/ansible module securely bootstraps your host (LXC, VPS, cloud), installing basic dependencies such as uv, Git, and the optional static PostgreSQL/Redis core infrastructure elements.
  2. ContextUnity Sourcing: The monorepo is idempotently cloned via git.
  3. Template Segregation: Jinja2 bindings within the Ansible playbook inject target-specific .env.services parameters securely via Ansible Vault, completely bypassing plaintext configuration disk drops.
  4. Parameterized Service Grids: Dynamic systemd templates iterate to spin up identical processes mapping to variable instance targets (shared, commerce, news).

Systemd Process Orchestration

ContextUnity horizontal scalability pivots directly from native Linux templates @:

ExecStart=/opt/contextunity/services/cu/brain/uv run python -m contextbrain
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30

Every service strictly enforces Restart=on-failure policies with a required TimeoutStopSec=30 graceful shutdown capability. ContextUnity routes logging out of native system files to pipe logs exclusively onto journald to natively support global telemetry extraction loops.

Systemd Credentials (Secret Hardening)

ContextUnity supports systemd-creds for encrypting secrets at rest. Instead of storing API keys and encryption keys in plaintext .env files, secrets are encrypted to /etc/credstore.encrypted/ and decrypted at runtime by systemd into CREDENTIALS_DIRECTORY.

How it works

  1. Ansible provisions encrypted credentials during deployment:

    # In cu_service role — deploy_one.yml
    - name: Provision encrypted systemd credentials
    shell: |
    echo -n "{{ item.value }}" | systemd-creds encrypt \
    --name={{ item.name }} - \
    /etc/credstore.encrypted/{{ svc }}_{{ item.name }}
    loop: "{{ svc_cfg.credentials | default([]) }}"
    no_log: true
  2. Systemd unit loads credentials at service start:

    # In service.j2 template
    LoadCredentialEncrypted=shield_master_key:/etc/credstore.encrypted/shield_shield_master_key
  3. Service reads via _read_credential() from contextunity.core.config:

    from contextunity.core.config import _read_credential
    # Checks CREDENTIALS_DIRECTORY first, falls back to env var
    secret = _read_credential("shield_master_key", os.getenv("SHIELD_MASTER_KEY", ""))

Secret Inventory

ServiceCredentialEnv Fallback
Shieldshield_master_keySHIELD_MASTER_KEY
Shieldshield_encryption_keySHIELD_ENCRYPTION_KEY
Routercu_project_secretCU_PROJECT_SECRET
Routerredis_secret_keyREDIS_SECRET_KEY
Workerredis_secret_keyREDIS_SECRET_KEY
Viewdjango_secret_keySECRET_KEY

Ansible Configuration

Define credentials per service in your inventory:

cu_services:
shield:
credentials:
- { name: shield_master_key, value: "{{ vault_shield_master_key }}" }
- { name: shield_encryption_key, value: "{{ vault_shield_encryption_key }}" }
router:
credentials:
- { name: cu_project_secret, value: "{{ vault_cu_project_secret }}" }
- { name: redis_secret_key, value: "{{ vault_redis_secret_key }}" }

Security Hardening

All service units include hardening directives:

NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/tmp /var/log/contextunity /opt/contextunity
PrivateTmp=true

Combined with systemd-creds, this ensures secrets are:

  • Encrypted at rest on disk (/etc/credstore.encrypted/, mode 0700)
  • Decrypted only in memory by the service process
  • Never visible in .env files, process environment listings, or Ansible logs (no_log: true)