chore: add new role for OpnForm
This commit is contained in:
parent
14c81657d7
commit
eb51b6a054
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 }}"
|
||||
```
|
||||
71
roles/OpnForm/defaults/main.yml
Normal file
71
roles/OpnForm/defaults/main.yml
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# defaults file for opnform
|
||||
|
||||
# Base directory configuration (inherited from base role or defined here)
|
||||
docker_compose_base_dir: /etc/docker/compose
|
||||
docker_volume_base_dir: /srv/data
|
||||
|
||||
# opnform-specific configuration
|
||||
opnform_service_name: opnform
|
||||
opnform_docker_compose_dir: "{{ docker_compose_base_dir }}/{{ opnform_service_name }}"
|
||||
opnform_docker_volume_dir: "{{ docker_volume_base_dir }}/{{ opnform_service_name }}"
|
||||
opnform_storage_dir: "{{ opnform_docker_volume_dir }}/storage"
|
||||
opnform_db_data_dir: "{{ opnform_docker_volume_dir }}/db"
|
||||
opnform_redis_data_dir: "{{ opnform_docker_volume_dir }}/redis"
|
||||
|
||||
# Service configuration
|
||||
opnform_domain: "forms.local.test"
|
||||
opnform_base_url: "https://forms.local.test"
|
||||
|
||||
# Images
|
||||
opnform_api_image: "jhumanj/opnform-api:latest"
|
||||
opnform_client_image: "jhumanj/opnform-client:latest"
|
||||
opnform_redis_image: "redis:7"
|
||||
opnform_db_image: "postgres:16"
|
||||
opnform_ingress_image: "nginx:1"
|
||||
|
||||
# REQUIRED SECRETS — generate with: openssl rand -base64 32
|
||||
# Always prefix opnform_app_key with "base64:"
|
||||
# Provide via OpenBao lookup, Ansible Vault or extra-vars.
|
||||
# Never commit real keys to version control.
|
||||
opnform_app_key: "base64:vsQw8EoC64nmhurLUUohXUlAeryaV6Y2Is64Tdvjlko="
|
||||
opnform_jwt_secret: "0b2e8ed326334a08ce3846bfcd6588f5a11be33999e96963cd4eaff1a3ae828b"
|
||||
opnform_front_api_secret: "8f52397785a110b657f2a6beab13362877bfac936ae9002bc236c54ed1011b2d"
|
||||
|
||||
# Database credentials
|
||||
opnform_db_name: "opnform"
|
||||
opnform_db_user: "opnform"
|
||||
opnform_db_password: "xtNLUVc2ajcWictqWXWkLR"
|
||||
|
||||
# PHP configuration
|
||||
opnform_php_memory_limit: "1G"
|
||||
opnform_php_max_execution_time: "600"
|
||||
opnform_php_upload_max_filesize: "64M"
|
||||
opnform_php_post_max_size: "64M"
|
||||
|
||||
# Nginx ingress
|
||||
opnform_nginx_max_body_size: "64m"
|
||||
|
||||
# Mail configuration (optional — defaults to log driver)
|
||||
opnform_mail_mailer: "log"
|
||||
opnform_mail_host: ""
|
||||
opnform_mail_port: ""
|
||||
opnform_mail_username: ""
|
||||
opnform_mail_password: ""
|
||||
opnform_mail_encryption: ""
|
||||
opnform_mail_from_address: "noreply@digitalboard.ch"
|
||||
opnform_mail_from_name: "OpnForm"
|
||||
|
||||
# OIDC configuration (Stage 1: not auto-configured, set up via UI after deploy)
|
||||
opnform_oidc_enabled: false
|
||||
opnform_oidc_issuer: "https://auth.digitalboard.ch/realms/Digitalboard"
|
||||
opnform_oidc_client_id: "opnform-digitalboard"
|
||||
opnform_oidc_client_secret: ""
|
||||
opnform_oidc_client_name: "Digitalboard"
|
||||
opnform_oidc_scopes: "openid profile email groups"
|
||||
opnform_oidc_admin_group: "opnform-admins"
|
||||
|
||||
# Traefik configuration
|
||||
opnform_traefik_network: "proxy"
|
||||
opnform_use_ssl: true
|
||||
8
roles/OpnForm/handlers/main.yml
Normal file
8
roles/OpnForm/handlers/main.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# handlers file for opnform
|
||||
|
||||
- name: restart opnform
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ opnform_docker_compose_dir }}"
|
||||
state: restarted
|
||||
35
roles/OpnForm/meta/main.yml
Normal file
35
roles/OpnForm/meta/main.yml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
galaxy_info:
|
||||
author: your name
|
||||
description: your role description
|
||||
company: your company (optional)
|
||||
|
||||
# If the issue tracker for your role is not on github, uncomment the
|
||||
# next line and provide a value
|
||||
# issue_tracker_url: http://example.com/issue/tracker
|
||||
|
||||
# Choose a valid license ID from https://spdx.org - some suggested licenses:
|
||||
# - BSD-3-Clause (default)
|
||||
# - MIT
|
||||
# - GPL-2.0-or-later
|
||||
# - GPL-3.0-only
|
||||
# - Apache-2.0
|
||||
# - CC-BY-4.0
|
||||
license: license (GPL-2.0-or-later, MIT, etc)
|
||||
|
||||
min_ansible_version: 2.2
|
||||
|
||||
# If this a Container Enabled role, provide the minimum Ansible Container version.
|
||||
# min_ansible_container_version:
|
||||
|
||||
galaxy_tags: []
|
||||
# List tags for your role here, one per line. A tag is a keyword that describes
|
||||
# and categorizes the role. Users find roles by searching for tags. Be sure to
|
||||
# remove the '[]' above, if you add tags to this list.
|
||||
#
|
||||
# NOTE: A tag is limited to a single word comprised of alphanumeric characters.
|
||||
# Maximum 20 tags per role.
|
||||
|
||||
dependencies: []
|
||||
# List your role dependencies here, one per line. Be sure to remove the '[]' above,
|
||||
# if you add dependencies to this list.
|
||||
117
roles/OpnForm/tasks/main.yml
Normal file
117
roles/OpnForm/tasks/main.yml
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# tasks file for opnform
|
||||
|
||||
# =====================================================================
|
||||
# 0. VALIDATION
|
||||
# =====================================================================
|
||||
|
||||
- name: Validate required secrets
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- opnform_app_key | length > 0
|
||||
- opnform_app_key is match('^base64:[A-Za-z0-9+/=]+$')
|
||||
- opnform_jwt_secret | length > 0
|
||||
- opnform_front_api_secret | length > 0
|
||||
- opnform_db_password | length > 0
|
||||
fail_msg: >-
|
||||
OpnForm requires opnform_app_key (prefix 'base64:'), opnform_jwt_secret,
|
||||
opnform_front_api_secret and opnform_db_password.
|
||||
Generate with: openssl rand -base64 32
|
||||
The app_key MUST be prefixed with "base64:"
|
||||
Provide via OpenBao, Ansible Vault or extra-vars.
|
||||
success_msg: Secrets validation passed
|
||||
|
||||
- name: Validate OIDC configuration when enabled
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- opnform_oidc_client_secret | length > 0
|
||||
fail_msg: >-
|
||||
opnform_oidc_client_secret must be set when opnform_oidc_enabled is true.
|
||||
when: opnform_oidc_enabled | bool
|
||||
|
||||
# =====================================================================
|
||||
# 1. PREPARATION
|
||||
# =====================================================================
|
||||
|
||||
- name: Ensure required packages are installed
|
||||
ansible.builtin.package:
|
||||
name:
|
||||
- python3-docker
|
||||
state: present
|
||||
|
||||
- name: Create docker compose directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ opnform_docker_compose_dir }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Create OpnForm data directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ opnform_docker_volume_dir }}"
|
||||
- "{{ opnform_storage_dir }}"
|
||||
- "{{ opnform_db_data_dir }}"
|
||||
- "{{ opnform_redis_data_dir }}"
|
||||
|
||||
# =====================================================================
|
||||
# 2. CONFIGURATION FILES
|
||||
# =====================================================================
|
||||
|
||||
- name: Deploy nginx ingress configuration
|
||||
ansible.builtin.template:
|
||||
src: nginx.conf.j2
|
||||
dest: "{{ opnform_docker_compose_dir }}/nginx.conf"
|
||||
mode: '0644'
|
||||
notify: restart opnform
|
||||
|
||||
- name: Deploy docker-compose file
|
||||
ansible.builtin.template:
|
||||
src: docker-compose.yml.j2
|
||||
dest: "{{ opnform_docker_compose_dir }}/docker-compose.yml"
|
||||
mode: '0644'
|
||||
notify: restart opnform
|
||||
|
||||
# =====================================================================
|
||||
# 3. CONTAINER STARTUP
|
||||
# =====================================================================
|
||||
|
||||
- name: Start opnform containers
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ opnform_docker_compose_dir }}"
|
||||
state: present
|
||||
wait: true
|
||||
wait_timeout: 180
|
||||
|
||||
# =====================================================================
|
||||
# 4. WAIT FOR API READINESS
|
||||
# =====================================================================
|
||||
|
||||
- name: Wait for API container to be healthy
|
||||
ansible.builtin.command:
|
||||
cmd: docker inspect --format='{% raw %}{{.State.Health.Status}}{% endraw %}' opnform-api
|
||||
register: api_health
|
||||
until: api_health.stdout == "healthy"
|
||||
retries: 30
|
||||
delay: 10
|
||||
changed_when: false
|
||||
|
||||
- name: Display deployment info
|
||||
ansible.builtin.debug:
|
||||
msg: |-
|
||||
OpnForm deployed at {{ opnform_base_url }}
|
||||
|
||||
Default credentials (from API container logs on first start):
|
||||
Email: admin@opnform.com
|
||||
Password: password
|
||||
|
||||
On first login you will be prompted to change email and password.
|
||||
|
||||
If login does not respond, the DB seed may have failed. Run:
|
||||
docker compose -f {{ opnform_docker_compose_dir }}/docker-compose.yml exec api php artisan migrate:refresh --seed
|
||||
docker compose -f {{ opnform_docker_compose_dir }}/docker-compose.yml exec api php artisan app:init-project
|
||||
|
||||
OIDC: {% if opnform_oidc_enabled %}enabled (configure via Admin UI){% else %}disabled{% endif %}
|
||||
189
roles/OpnForm/templates/docker-compose.yml.j2
Normal file
189
roles/OpnForm/templates/docker-compose.yml.j2
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
#---------------------------------------------------------------------#
|
||||
# OpnForm — Beautiful open-source form builder #
|
||||
#---------------------------------------------------------------------#
|
||||
services:
|
||||
api: &api-service
|
||||
image: {{ opnform_api_image }}
|
||||
container_name: opnform-api
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- {{ opnform_storage_dir }}:/usr/share/nginx/html/storage:rw
|
||||
environment: &api-env
|
||||
APP_ENV: production
|
||||
APP_KEY: "{{ opnform_app_key }}"
|
||||
APP_URL: "{{ opnform_base_url }}"
|
||||
APP_DEBUG: "false"
|
||||
SELF_HOSTED: "true"
|
||||
|
||||
LOG_CHANNEL: errorlog
|
||||
LOG_LEVEL: info
|
||||
|
||||
DB_CONNECTION: pgsql
|
||||
DB_HOST: db
|
||||
DB_PORT: "5432"
|
||||
DB_DATABASE: "{{ opnform_db_name }}"
|
||||
DB_USERNAME: "{{ opnform_db_user }}"
|
||||
DB_PASSWORD: "{{ opnform_db_password }}"
|
||||
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: "6379"
|
||||
|
||||
CACHE_STORE: redis
|
||||
CACHE_DRIVER: redis
|
||||
QUEUE_CONNECTION: redis
|
||||
SESSION_DRIVER: redis
|
||||
SESSION_LIFETIME: "120"
|
||||
BROADCAST_CONNECTION: log
|
||||
|
||||
FILESYSTEM_DISK: local
|
||||
FILESYSTEM_DRIVER: local
|
||||
LOCAL_FILESYSTEM_VISIBILITY: public
|
||||
|
||||
MAIL_MAILER: "{{ opnform_mail_mailer }}"
|
||||
MAIL_HOST: "{{ opnform_mail_host }}"
|
||||
MAIL_PORT: "{{ opnform_mail_port }}"
|
||||
MAIL_USERNAME: "{{ opnform_mail_username }}"
|
||||
MAIL_PASSWORD: "{{ opnform_mail_password }}"
|
||||
MAIL_ENCRYPTION: "{{ opnform_mail_encryption }}"
|
||||
MAIL_FROM_ADDRESS: "{{ opnform_mail_from_address }}"
|
||||
MAIL_FROM_NAME: "{{ opnform_mail_from_name }}"
|
||||
|
||||
JWT_TTL: "1440"
|
||||
JWT_SECRET: "{{ opnform_jwt_secret }}"
|
||||
|
||||
PHP_MEMORY_LIMIT: "{{ opnform_php_memory_limit }}"
|
||||
PHP_MAX_EXECUTION_TIME: "{{ opnform_php_max_execution_time }}"
|
||||
PHP_UPLOAD_MAX_FILESIZE: "{{ opnform_php_upload_max_filesize }}"
|
||||
PHP_POST_MAX_SIZE: "{{ opnform_php_post_max_size }}"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "php /usr/share/nginx/html/artisan about || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 15s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
networks:
|
||||
- opnform-internal
|
||||
|
||||
api-worker:
|
||||
<<: *api-service
|
||||
container_name: opnform-api-worker
|
||||
command: ["php", "artisan", "queue:work"]
|
||||
environment:
|
||||
<<: *api-env
|
||||
IS_API_WORKER: "true"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pgrep -f 'php artisan queue:work' > /dev/null || exit 1"]
|
||||
interval: 60s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
api-scheduler:
|
||||
<<: *api-service
|
||||
container_name: opnform-api-scheduler
|
||||
command: ["php", "artisan", "schedule:work"]
|
||||
healthcheck:
|
||||
test:
|
||||
- "CMD-SHELL"
|
||||
- "php /usr/share/nginx/html/artisan app:scheduler-status --mode=check --max-minutes=3 || exit 1"
|
||||
interval: 60s
|
||||
timeout: 30s
|
||||
retries: 3
|
||||
start_period: 70s
|
||||
|
||||
ui:
|
||||
image: {{ opnform_client_image }}
|
||||
container_name: opnform-ui
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
NUXT_PUBLIC_APP_URL: "{{ opnform_base_url }}"
|
||||
NUXT_PUBLIC_API_BASE: "/api"
|
||||
NUXT_PRIVATE_API_BASE: "http://ingress/api"
|
||||
NUXT_PUBLIC_ENV: production
|
||||
FRONT_API_SECRET: "{{ opnform_front_api_secret }}"
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget --spider -q http://localhost:3000/login || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 45s
|
||||
networks:
|
||||
- opnform-internal
|
||||
|
||||
redis:
|
||||
image: {{ opnform_redis_image }}
|
||||
container_name: opnform-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- {{ opnform_redis_data_dir }}:/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
networks:
|
||||
- opnform-internal
|
||||
|
||||
db:
|
||||
image: {{ opnform_db_image }}
|
||||
container_name: opnform-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: "{{ opnform_db_name }}"
|
||||
POSTGRES_USER: "{{ opnform_db_user }}"
|
||||
POSTGRES_PASSWORD: "{{ opnform_db_password }}"
|
||||
volumes:
|
||||
- {{ opnform_db_data_dir }}:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U {{ opnform_db_user }}"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
networks:
|
||||
- opnform-internal
|
||||
|
||||
ingress:
|
||||
image: {{ opnform_ingress_image }}
|
||||
container_name: opnform-ingress
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/templates/default.conf.template:ro
|
||||
environment:
|
||||
NGINX_MAX_BODY_SIZE: "{{ opnform_nginx_max_body_size }}"
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_started
|
||||
ui:
|
||||
condition: service_started
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "nginx -t && curl -f http://localhost/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
networks:
|
||||
- opnform-internal
|
||||
- {{ opnform_traefik_network }}
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.docker.network={{ opnform_traefik_network }}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.rule=Host(`{{ opnform_domain }}`)
|
||||
{% if opnform_use_ssl %}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.entrypoints=websecure
|
||||
- traefik.http.routers.{{ opnform_service_name }}.tls=true
|
||||
{% else %}
|
||||
- traefik.http.routers.{{ opnform_service_name }}.entrypoints=web
|
||||
{% endif %}
|
||||
- traefik.http.services.{{ opnform_service_name }}.loadbalancer.server.port=80
|
||||
|
||||
networks:
|
||||
opnform-internal:
|
||||
driver: bridge
|
||||
{{ opnform_traefik_network }}:
|
||||
external: true
|
||||
43
roles/OpnForm/templates/nginx.conf.j2
Normal file
43
roles/OpnForm/templates/nginx.conf.j2
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
map $original_uri $api_uri {
|
||||
~^/api(/.*$) $1;
|
||||
default $original_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name {{ opnform_domain }};
|
||||
root /app/public;
|
||||
|
||||
client_max_body_size {% raw %}${NGINX_MAX_BODY_SIZE}{% endraw %};
|
||||
|
||||
access_log /dev/stdout;
|
||||
error_log /dev/stderr error;
|
||||
|
||||
index index.html index.htm index.php;
|
||||
|
||||
location / {
|
||||
proxy_http_version 1.1;
|
||||
proxy_pass http://ui:3000;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
}
|
||||
|
||||
location ~/(api|open|local\/temp|forms\/assets)/ {
|
||||
set $original_uri $uri;
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass api:9000;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html/public/index.php;
|
||||
fastcgi_param REQUEST_URI $api_uri;
|
||||
}
|
||||
}
|
||||
2
roles/OpnForm/tests/inventory
Normal file
2
roles/OpnForm/tests/inventory
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
localhost
|
||||
6
roles/OpnForm/tests/test.yml
Normal file
6
roles/OpnForm/tests/test.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
- hosts: localhost
|
||||
remote_user: root
|
||||
roles:
|
||||
- OpnForm
|
||||
3
roles/OpnForm/vars/main.yml
Normal file
3
roles/OpnForm/vars/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
# vars file for homarr
|
||||
Loading…
Add table
Add a link
Reference in a new issue