Servidor y base de datos

El servidor web, la conexión a MySQL, la cuenta de admin y lo que ejecuta cada proceso (AF_ROLE y las variables RTE_*)

  1. Ejemplo
  2. Variables

Cambia estas variables cuando la aplicación se ejecuta detrás de un proxy inverso, en otro puerto o contra una base de datos fuera del proyecto compose.


Ejemplo

Detrás de un proxy inverso que termina TLS, bajo /ansibleforms, con un MySQL externo. En docker-compose.yml:

    environment:
      - BASE_URL=/ansibleforms        # the proxy forwards /ansibleforms/ unchanged
      - HTTPS=0                       # the proxy terminates TLS
      - PORT=8000
      - DB_HOST=mysql.example.com
      - DB_PORT=3306
      - DB_USER=ansibleforms
      - DB_PASSWORD=change-me

Estas líneas sustituyen a las líneas DB_* y PORT que el archivo compose ya tiene ahí, que ganan a los mismos nombres en .env. Quita el servicio mysqldb y el depends_on que lo espera, y mapea el puerto 8000 en ports. La parte del proxy se describe en la página Proxy inverso.


Variables

Todas las variables de este grupo, con su tipo, su valor predeterminado y su descripción:

Variable Opciones/Valores predeterminados Comentarios
NODE_ENV
string
Valor predeterminado:
production

The Node.js environment
a valid nodejs environment

Nodejs can have multiple environments, like development or production

DB_HOST
string / required

Database host
a valid IP or FQDN

AnsibleForms requires a MySQL database connection to store the configuration of the application.

DB_PORT
number / required
added in version 6.3.0

Database port
a positive integer

Port of the MySQL or MariaDB server, usually 3306. It has no default: the server refuses to start when DB_PORT, DB_HOST, DB_USER or DB_PASSWORD is not set, and changing it needs a restart.

DB_USER
string / required

Database user
a valid mysql user

AnsibleForms requires a MySQL database connection to store the configuration of the application.

Give it a user of its own with rights on its schema only - not root:

CREATE USER 'ansibleforms'@'%' IDENTIFIED BY '<password>';
GRANT ALL PRIVILEGES ON `AnsibleForms`.* TO 'ansibleforms'@'%';

That is all the application needs: it creates and patches its schema, makes its backups, and ends a dead worker’s session (its own sessions, which needs no further right). A user with rights on every database turns any hole in the application into a hole in the whole database server ; the Status page and the log say so when the user has them.

DB_PASSWORD
string / required Secreto

Database password
a valid mysql password

AnsibleForms requires a MySQL database connection to store the configuration of the application.

DB_POOL_SIZE
number
Valor predeterminado:
20

Database connection pool size
a positive integer

Maximum number of concurrent MySQL connections kept in the pool. All database queries share this pool instead of opening a new connection per query, which dramatically reduces connection overhead and improves throughput under load. Increase this if you have many concurrent users or long-running cron-driven jobs; decrease it if your MySQL server has a low max_connections limit.

PORT
number
Valor predeterminado:
8000

HTTP port
a valid TCP port

The listening port of the web application

BASE_URL
string
Valor predeterminado:
/

URL subpath to host the application under
a url subpath, for example /ansibleforms

Host the whole application (GUI, REST API and Swagger interface) under a URL subpath, typically behind a reverse proxy. For example with BASE_URL=/ansibleforms, the application is served under https://host/ansibleforms/. Note: when using an SSO identity provider (Microsoft Entra ID / OIDC), make sure the instance url in the provider settings includes the subpath, so the generated redirect uri matches.

TRUST_PROXY
string
added in version 7.0.0
Valor predeterminado:
0

Trusted reverse proxies
0, a number of proxies, true, or a comma-separated list of proxy addresses and CIDR ranges

Behind a reverse proxy (nginx, traefik, a kubernetes ingress, a load balancer) every connection comes from the proxy, so without this setting the audit trail records the proxy’s address for every action. Set it to tell the application which proxies it may believe when they report the real client address in the X-Forwarded-For header. It is passed to the Express trust proxy setting:

  • 0 (default): trust no proxy, the address of the connection is recorded
  • a number, for example 1: trust that many proxies in front of the application (1 = a single reverse proxy). Use the exact count: a higher number lets a client choose the recorded address
  • a comma-separated list of proxy addresses and CIDR ranges, for example 10.0.0.5,172.16.0.0/12, or the presets loopback, linklocal and uniquelocal
  • true: trust every hop, the left-most X-Forwarded-For address is recorded

Security: X-Forwarded-For is an ordinary request header that any client can send. Only trust proxies that are really in front of the application and that set or overwrite the header themselves, otherwise a client chooses the address the audit trail records. Never use true unless the application is reachable only through the proxy; prefer the number of proxies or their addresses.

DEFAULT_LANGUAGE
string
Valor predeterminado:
en

Default language
ca, de, en, es, fr, it, nl, pl, pt, ja, zh

Sets the language for the application, for users who have not picked their own with the language switcher. The chosen language is persisted in a cookie. Both frontend UI and backend error messages are translated.

HTTPS
number
Opciones:
  • 0 (predeterminado)
  • 1

Enable HTTPS
0, 1

Our docker-compose comes with sample certificates. It is highly recommended to enable HTTPS.

HTTPS_KEY
string
Valor predeterminado:
%PERSISTENT_FOLDER%/certificates/key.pem

HTTPS private key
a valid file path

The path to the private key of the server certificate, in BASE64/PEM format.

HTTPS_CERT
string
Valor predeterminado:
%PERSISTENT_FOLDER%/certificates/cert.pem

HTTPS certificate
a valid file path

The path to the server certificate, in BASE64/PEM format.

ADMIN_USERNAME
string
added in version 5.0.8
Valor predeterminado:
admin

Admin username
a valid username

The admin username is the first user that can login to the application.
This user has full access to the application and is created at first start if not present. This user will be added to the admins group, which will be created as well if not present.

ADMIN_PASSWORD
string Secreto
added in version 5.0.8
Valor predeterminado:
AnsibleForms!123

Admin password
a valid password

The admin password is the password for first user that can login to the application.
This user has full access to the application and is created at first start if not present. This user will be added to the admins group, which will be created as well if not present.

AF_ROLE
string
added in version 7.0.0
Valor predeterminado:
all

What this process runs
all, app, worker, rte

all (the default, or unset) is AnsibleForms as it always ran: the web app and the worker in one process. To run several app nodes behind a load balancer, split them: app serves the web interface and the API only (as many as you like, each with the same ACCESS_TOKEN_SECRET), and worker runs the background work only - the database bootstrap and seed, the schedules, the nightly backup, the repository syncs and the cleanups. One worker works at a time ; a second one waits and takes over when the first stops. App nodes and the worker share the database and the persistent volume.

rte starts the same image as a runtime environment that runs playbooks for an app, with no web interface, scheduler or seed. How it talks to the app is RTE_MODE: over one WebSocket (outbound, it dials the app at APP_URL ; inbound, the app dials it at RTE_URL), holding no database credentials ; or, deprecated, reading and writing the app’s database itself (database, with DB_* and the same ENCRYPTION_SECRET). Either way it needs RTE_TOKEN.

RTE_MODE
string
added in version 7.3.0
Valor predeterminado:
database

How an RTE talks to the app
outbound, inbound or database

Read by an RTE (AF_ROLE=rte).

outbound: the RTE dials the app (APP_URL) and keeps one WebSocket open, redialing when it drops. Nothing reaches the RTE from outside: only its zone to the app on the app’s port, through a proxy if HTTPS_PROXY says so. The first time it joins with RTE_JOIN_TOKEN.

HTTPS_PROXY and NO_PROXY (lower case read too) are the system’s own proxy variables, set on the RTE’s container rather than here, and a playbook keeps them: the socket to the app and an inbound RTE’s registration call go through HTTPS_PROXY, unless the app’s host is in NO_PROXY (host names, .domain suffixes, or * for every host).

A dial that fails is logged at warning with its cause and a hint: a name that does not resolve, nothing listening, a certificate not trusted or not for that name, a proxy, or the app refusing the socket (401 the token, 404 the APP_URL path or BASE_URL). The first failure and every change of cause are logged at once, the same cause again at most every 5 minutes while it lasts, and reaching the app again at notice. The app does the same for an inbound RTE it cannot dial. The token is never logged.

inbound: the RTE listens and the app dials it at its runner’s address (RTE_URL), one app node at a time. With APP_URL (and RTE_JOIN_TOKEN the first time) it registers itself with one call ; without, add its runner under Connections > Runners (type RTE, mode inbound, its address and RTE_TOKEN).

In both socket modes the RTE holds no database credentials: the app sends it each job and stores what comes back - the output, the events, the end - exactly once, and sends the end notifications. The job’s files come with it unless RTE_FILES=local.

database (deprecated, removed in 8.0.0): the RTE reads and writes the app’s database itself, with DB_* and the same ENCRYPTION_SECRET - the only mode before 7.3, and the one of an RTE without RTE_MODE throughout 7.x. It logs a deprecation warning at its start.

APP_URL
string
added in version 7.3.0

The app's address an RTE dials
an http:// or https:// address

On an RTE in outbound mode: the app’s address as people open it - https://forms.example.com, with its BASE_URL if any. The RTE adds the socket’s path (/api/v2/rte/socket) and dials it over wss:// (ws:// for an http address).

On an RTE in inbound mode: the address of its one registration call (with RTE_URL and, the first time, RTE_JOIN_TOKEN) ; the app dials it from then on.

The certificate is checked: name a private CA with NODE_EXTRA_CA_CERTS, or turn the check off inside one trusted network with APP_TLS_VERIFY=0.

APP_TLS_VERIFY
number
added in version 7.3.0
Valor predeterminado:
1

Whether an RTE checks the app's certificate
0 or 1

On an RTE that dials the app (APP_URL). 1: the app’s certificate must be valid for its name (a private CA through NODE_EXTRA_CA_CERTS). 0: any certificate is accepted - only inside one trusted network, such as a compose project or a pod, where the app’s certificate is self-signed.

RTE_JOIN_TOKEN
string Secreto
added in version 7.3.0

The token an RTE joins the app with, once
a join token of Connections > Runners (afj_...)

On an RTE in a socket mode, the first time, optional. Without it an RTE the app does not know asks to join and waits for an admin’s approval under Connections > Runners. With it the RTE is approved at once - for unattended installs - and the app adds it as a runner (or gives a runner of that name still waiting for approval the new token ; an approved runner keeps its token, which only an admin changes). Join tokens are made through the API (POST /api/v2/runner/jointoken, an admin). From then on the RTE signs in with its own token ; the join token can expire or be revoked without affecting it.

RTE_NAME
string
added in version 7.3.0

The runner name an RTE joins as
letters, digits and . _ - : @

On an RTE in a socket mode: the name of its runner under Connections > Runners, which forms name with runner:. Not set: its node id (rte-<hostname>-<port>), which changes when the container is recreated - set it in production.

RTE_FILES
string
added in version 7.3.0
Valor predeterminado:
transfer

Where a socket-mode RTE gets a job's files
transfer or local

On an RTE in a socket mode. transfer: the app sends the playbooks folder and the inventories with the job, packed and named by a hash of their content ; the RTE keeps them packed (RTE_CACHE_PATH) and an unchanged folder is never sent twice. Each job unpacks them in a private folder of its own, removed when it ends. It needs no shared disk and no access to the repositories. local: the RTE runs from its own folders, as a database-mode RTE - mount the playbooks (ANSIBLE_PATH) and repositories (REPO_PATH). It can be set on the runner page (Connections > Runners > the runner > RTE) ; a value there wins over this one.

RTE_FILES_MAX_MB
number
added in version 7.3.0
Valor predeterminado:
512

The largest folder the app sends an RTE
a positive integer

Read by the app: a playbooks or inventory folder bigger than this is not sent to an RTE with RTE_FILES=transfer ; the job fails and says to mount the folder on the RTE instead.

RTE_SPOOL_PATH
string
added in version 7.3.0
Valor predeterminado:
%PERSISTENT_FOLDER%/rte-spool

Where a socket-mode RTE keeps what the app has not stored yet

On an RTE in a socket mode: each job’s output, events and end wait here until the app acks them, and are sent again after a reconnect - to the same app node or another. On a volume, an RTE that restarts sends what it had not delivered.

RTE_CACHE_PATH
string
added in version 7.3.0
Valor predeterminado:
%PERSISTENT_FOLDER%/rte-files

Where a socket-mode RTE keeps the job files the app sent

On an RTE with RTE_FILES=transfer: the playbooks and inventory folders the app sent, packed, each under its hash ; those used most recently are kept, up to RTE_CACHE_MB. Each running job unpacks them under jobs/ in a private folder, removed when the job ends.

RTE_CACHE_MB
number
added in version 7.3.0
Valor predeterminado:
1024

The size of a socket-mode RTE's job files cache
0 or a positive integer

On an RTE with RTE_FILES=transfer: how much the job files it keeps (RTE_CACHE_PATH) may take, in MB. The ones used longest ago go first ; 0 keeps none, so the app sends a job’s files with every job. It can be set on the runner page (Connections > Runners > the runner > RTE) ; a value there wins over this variable.

RTE_TOKEN
string Secreto
added in version 7.0.0

The token between an app and its RTE
at least 16 characters

On an RTE (AF_ROLE=rte): the bearer token every call must carry ; the RTE refuses to start without one. The app stores the same token on the runner (Connections > Runners) ; a socket-mode RTE that joins (RTE_JOIN_TOKEN or an admin’s approval) puts it there. A database-mode RTE that registers itself (RTE_REGISTER) does too, and keeps it in step.

RTE_REGISTER
number
added in version 7.0.0
Valor predeterminado:
1

A database-mode RTE adds itself as a runner (deprecated)
0 or 1

Deprecated since 7.3.0, removed in 8.0.0 with database mode. Read only by an RTE in database mode (no RTE_MODE, or RTE_MODE=database). An RTE in a socket mode (outbound or inbound) ignores it: it joins with RTE_JOIN_TOKEN, or asks to join and waits for an admin’s approval under Connections > Runners.

On a database-mode RTE: 1 (the default) and the RTE adds itself under Connections > Runners when it starts, and checks every 30 seconds that it is still there. The first RTE becomes the default runner. Its address is RTE_URL, or this container’s IP address and PORT when that is not set.

A runner the RTE registered shows as automatic on the Runners page, and as unresponsive once the RTE stopped writing its heartbeat ; the worker removes it 10 minutes later. A recreated container registers again under its new address and takes the default from the one that stopped. A runner added by hand at the same address stays yours (its token follows RTE_TOKEN) ; one from the config seed is never touched.

0: the RTE does not register itself ; add it under Connections > Runners or in the seed.

RTE_MAX_JOBS
number
added in version 7.0.0
Valor predeterminado:
10

How many playbooks an RTE runs at once
0 or a positive integer

Read by an RTE (AF_ROLE=rte). A full RTE does not take another job: the job waits, says so in its output, and is handed over as soon as a playbook ends (see RTE_QUEUE_MINUTES). Size it to the RTE’s cpu and memory: every playbook is an ansible-playbook process with its forks. Run more RTE replicas to run more at once. On a socket-mode RTE it can be set on its runner page (Connections > Runners > the runner > RTE) ; a value there wins over this one.

RTE_DRAIN_SECONDS
number
added in version 7.0.0
Valor predeterminado:
25

How long a stopping RTE waits for its running playbooks
0 or a positive integer

Read by an RTE. On a stop (SIGTERM: a rolling update, a scale down) it takes no new job and waits this long for the running playbooks to end ; those still running then end as abandoned. Keep it below what the platform waits before it kills the container: Kubernetes’ terminationGracePeriodSeconds (30 by default), docker stop’s –time (10). On a socket-mode RTE it can be set on its runner page ; a value there wins over this one.

RTE_QUEUE_MINUTES
number
added in version 7.0.0
Valor predeterminado:
60

Wait for a busy or disconnected RTE (minutes)
0 or a positive integer

A job handed to an RTE that is full (RTE_MAX_JOBS) or stopping waits for it, asking again every 10 seconds, for this many minutes ; then it fails and says why. An abort ends the wait at once. It also covers the running jobs of a socket-mode RTE (outbound, inbound) whose connection dropped: their playbooks run on and the RTE keeps their output, so they stay running for this many minutes and go on when it reconnects, or end as abandoned after that (or at once when the RTE comes back without them). 0 waits for ever.

LISTEN_HOST
string
added in version 7.3.0

The address an RTE listens on
an IP address or host name of this machine

On an RTE (AF_ROLE=rte): the address its listener binds (its probes, its metrics and, inbound, the socket the app dials). Not set: every interface, as before. 127.0.0.1 keeps a native outbound RTE, which takes no call from the app, reachable from its own host only. An inbound RTE must listen where the app reaches it (RTE_URL).

RTE_URL
string
added in version 7.0.0

The address the app reaches an RTE on
an http:// or https:// address, without a slash on the end

On an RTE in inbound mode: the address the app dials it on, usually the service name - http://rte:8000 in docker compose, the service in kubernetes. It is required when the RTE registers itself with APP_URL (it refuses to start without it), and becomes its runner’s address. On an outbound RTE it is optional: it is only recorded as the runner’s address.

On a deprecated database-mode RTE that registers itself (RTE_REGISTER): the address it registers, its runner named after the host (rte). Not set: this container’s IP address and PORT, named after the node (rte-<hostname>-<port>), which change when it is recreated.

An inbound RTE (RTE_MODE=inbound) over TLS: set HTTPS=1 with its own HTTPS_CERT and HTTPS_KEY, and an https:// address here. When it registers (APP_URL) it sends its certificate, the app keeps it as the ca_bundle of the runner’s credential and dials the RTE pinned to it, whatever name the certificate was made for. A runner waiting for approval shows the certificate’s fingerprint, which the RTE logs at its start. Over plain http:// to another host the app sends RTE_TOKEN in clear, and says so in its log.

ALLOW_SCHEMA_CREATION
number
added in version 5.0.3
Opciones:
  • 0
  • 1 (predeterminado)

Allow schema creation
0, 1

With 1, the worker creates the schema (all AnsibleForms tables) itself at startup when it finds an empty database. It only does so on a database without a single AnsibleForms table, so an existing installation is never recreated. App nodes wait until the worker has created and patched the schema before they serve.

With 0, nothing creates the schema: the worker skips it at startup, the schema endpoint refuses to create it, and app nodes start without waiting for it. Set 0 to rule out any schema creation, for example on a production database.

The docker-compose MySQL only creates the empty AnsibleForms database and its user on its first start: the tables come from AnsibleForms, so keep 1 for a fresh install.

REINIT_ADMIN
number
added in version 6.0.0
Opciones:
  • 0 (predeterminado)
  • 1

Reset the local admin user/password at startup
0, 1

Recovery hatch when you’ve lost access to the local admin account. When set to 1, AnsibleForms will at startup:

  • ensure the admins group exists,
  • if the local admin user already exists, reset its password to the value of ADMIN_PASSWORD and re-attach it to the admins group,
  • if it doesn’t exist, create it (same as a fresh install).

The action is logged loudly. This is NOT a runtime auth bypass — once the admin is back in shape, unset REINIT_ADMIN and restart.

API_BODY_LIMIT_MB
number
added in version 6.0.0
Valor predeterminado:
50

Request body size limit (MB)

Cap on the size of JSON and urlencoded request bodies accepted by the AnsibleForms API. Default is 50 MB, generous enough for large form designs and heavy job extravars. Increase if you have unusually large forms or expression payloads. Note: this does NOT apply to file uploads (those are governed by UPLOAD_MAX_GB).

MAX_HTTP_HEADER_SIZE
number
added in version 7.1.0
Valor predeterminado:
16384

Request header size limit (bytes)
a number of bytes, from 1024 to 1048576

The largest request header the server accepts, in bytes. Node.js refuses a request whose headers are larger with 431 Request Header Fields Too Large, before it reaches the application, so nothing of it is in the log. Unset, Node’s own limit applies: 16384 bytes (16 KB), or the value of NODE_OPTIONS=--max-http-header-size when the deployment sets it. Raise it when a reverse proxy or a client sends large headers (large cookies, a large Authorization header). A value that is not a number from 1024 to 1048576 is ignored and logged. It applies to the web server, the RTE and the worker. The server reads it when it starts: a change takes effect after a restart.

UPLOAD_MAX_GB
number
added in version 6.0.0
Valor predeterminado:
10

Upload size limit (GB)

Cap on the size of a single file uploaded through the form upload field, in gigabytes. Default is 10 GB to accommodate large artifacts (e.g. firmware images, upgrade bundles). Set to 0 to disable the cap entirely (not recommended on shared instances).

PROCESS_MAX_BUFFER
number
added in version 5.0.8
Valor predeterminado:
50 * 1024 * 1024

The playbook output an RTE stores per stream
a valid number

Read by an RTE (AF_ROLE=rte): past this many bytes on one stream (stdout, stderr), a playbook’s output is no longer stored - one line in the job says so - and the playbook goes on to its end (until 7.0.0 it was stopped there, at 1 MiB by default). Since 7 the app runs no playbook itself, so set this in the RTE container’s environment ; it is not editable on the Settings page.