chore: add new role for OpnForm
This commit is contained in:
parent
9fc34dfb29
commit
6c1c40668d
10 changed files with 600 additions and 0 deletions
126
roles/OpnForm/README.md
Normal file
126
roles/OpnForm/README.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
# opnform
|
||||
|
||||
Deploy [OpnForm](https://github.com/OpnForm/OpnForm) as a self-contained
|
||||
Docker Compose stack behind Traefik.
|
||||
|
||||
## What this role does
|
||||
|
||||
- Deploys the full official OpnForm stack: `api`, `api-worker`, `api-scheduler`,
|
||||
`ui`, `db` (Postgres), `redis`, and `ingress` (nginx)
|
||||
- Configures all environment variables for self-hosted production use
|
||||
- Integrates the ingress container with an existing Traefik proxy network
|
||||
- Waits for the API container to become healthy before returning
|
||||
|
||||
## What this role does NOT do (stage 1)
|
||||
|
||||
- Does not pre-create an admin user (use the default credentials below)
|
||||
- Does not pre-configure OIDC / identity_connections — set up via Admin UI
|
||||
|
||||
## Architecture note: why two reverse proxies?
|
||||
|
||||
```
|
||||
Browser → Traefik (TLS, host routing) → ingress-nginx → api (PHP-FPM) / ui (Nuxt)
|
||||
```
|
||||
|
||||
The `ingress` container looks like a redundant proxy next to Traefik but
|
||||
does a different job. OpnForm's `api` image is **PHP-FPM only** — it
|
||||
speaks the FastCGI protocol on port 9000, not HTTP. Traefik cannot
|
||||
translate FastCGI, so the ingress nginx is required to:
|
||||
|
||||
- Translate HTTP `/api/*` requests into FastCGI calls to `api:9000`
|
||||
- Rewrite request URIs via the `$api_uri` map
|
||||
- Set Laravel-specific FastCGI params (`SCRIPT_FILENAME`, `REQUEST_URI`)
|
||||
- Reverse-proxy `/` to the Nuxt UI container on port 3000
|
||||
|
||||
Both containers run on the same Docker network on the same host, so the
|
||||
performance overhead of the extra hop is negligible (in-kernel memory
|
||||
copy, not a real network round-trip). Removing the ingress would require
|
||||
a custom OpnForm image with a built-in HTTP server, which is out of
|
||||
scope for this role.
|
||||
|
||||
## Required variables
|
||||
|
||||
Provide via OpenBao, Ansible Vault, or extra-vars. **Never commit real
|
||||
secrets to version control.**
|
||||
|
||||
| Variable | Format | Generate with |
|
||||
|---|---|---|
|
||||
| `opnform_app_key` | `base64:<32 bytes base64>` | `echo "base64:$(openssl rand -base64 32)"` |
|
||||
| `opnform_jwt_secret` | 32 bytes base64 | `openssl rand -base64 32` |
|
||||
| `opnform_front_api_secret` | 32 bytes base64 | `openssl rand -base64 32` |
|
||||
| `opnform_db_password` | strong password | `openssl rand -base64 24` |
|
||||
|
||||
When `opnform_oidc_enabled` is `true`:
|
||||
|
||||
| Variable | Source |
|
||||
|---|---|
|
||||
| `opnform_oidc_client_secret` | from your Keycloak/Authentik client |
|
||||
|
||||
The `assert` task at the top of the role will fail fast if any secret is
|
||||
missing or malformed.
|
||||
|
||||
## First login
|
||||
|
||||
After the role completes, OpnForm seeds a default admin user. Visit
|
||||
the URL in `opnform_base_url` and log in with:
|
||||
|
||||
- Email: `admin@opnform.com`
|
||||
- Password: `password`
|
||||
|
||||
On first login OpnForm will prompt you to change email and password.
|
||||
Self-hosted instances disable public registration after this — invite
|
||||
further users via the Admin UI.
|
||||
|
||||
### If the login does not respond
|
||||
|
||||
The DB seed may have failed. Re-run it manually:
|
||||
|
||||
```bash
|
||||
cd /etc/docker/compose/opnform
|
||||
docker compose exec api php artisan migrate:refresh --seed
|
||||
docker compose exec api php artisan app:init-project
|
||||
```
|
||||
|
||||
## OIDC setup (stage 2, not yet automated)
|
||||
|
||||
Manual setup via the Admin UI is currently the supported path:
|
||||
|
||||
1. Settings → Identity Connections → Add Connection
|
||||
2. Provider: OIDC
|
||||
3. Issuer: `https://auth.digitalboard.ch/realms/Digitalboard`
|
||||
4. Client ID / Secret: from your Keycloak client
|
||||
5. Add Group Role Mapping: Entra/Keycloak group Object ID → OpnForm role
|
||||
|
||||
Direct DB manipulation of `identity_connections` / `group_role_mappings`
|
||||
is possible but fragile across OpnForm versions. A future iteration of
|
||||
this role may automate it.
|
||||
|
||||
## Example playbook
|
||||
|
||||
```yaml
|
||||
- name: Deploy OpnForm service
|
||||
hosts: opnform_servers
|
||||
become: true
|
||||
roles:
|
||||
- digitalboard.core.opnform
|
||||
```
|
||||
|
||||
With inventory variables:
|
||||
|
||||
```yaml
|
||||
# group_vars/opnform_servers.yml
|
||||
opnform_domain: forms.digitalboard.ch
|
||||
opnform_base_url: "https://forms.digitalboard.ch"
|
||||
opnform_app_key: "{{ lookup('community.hashi_vault.vault_kv2_get',
|
||||
'digitalboard/opnform',
|
||||
mount_point='kv').data.data.app_key }}"
|
||||
opnform_jwt_secret: "{{ lookup('community.hashi_vault.vault_kv2_get',
|
||||
'digitalboard/opnform',
|
||||
mount_point='kv').data.data.jwt_secret }}"
|
||||
opnform_front_api_secret: "{{ lookup('community.hashi_vault.vault_kv2_get',
|
||||
'digitalboard/opnform',
|
||||
mount_point='kv').data.data.front_api_secret }}"
|
||||
opnform_db_password: "{{ lookup('community.hashi_vault.vault_kv2_get',
|
||||
'digitalboard/opnform',
|
||||
mount_point='kv').data.data.db_password }}"
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue