fepli
Hostingenterprise

Configuration

fepli is configured with environment variables, and only with them. The same set goes to all three containers that run the image, the web, the worker and the cron.

Give the web, worker and cron containers exactly the same variables. The worker writes the e-mails and the cron sends the reminders: a worker with a different database or mail server than the web container sends the wrong mail, or none. An env file shared by all three, as in the examples, is the simplest way.

Required

Set all of these in production. Without them, fepli doesn't start, or starts with defaults that are wrong for you.

fepli refuses to run while APP_SECRET is empty or a placeholder published with fepli or Symfony, such as ThisTokenIsNotSoSecretChangeIt or !ChangeMe!, and while INTEGRATIONS_ENCRYPTION_KEY is empty or a key published with fepli. The values earlier versions of the local setup used count as published for both. Requests then get an error page, and commands stop, the database migration at start among them. The message in the log names the variable to set. Only the dev and test environments are exempt; the image runs as prod.

  • Name
    APP_SECRET
    Type
    string
    Description

    Signs sessions, login links and form tokens. The image sets none, so every installation sets its own: openssl rand -hex 32. Changing it later signs everyone out and invalidates the links in e-mails already sent.

  • Name
    INTEGRATIONS_ENCRYPTION_KEY
    Type
    string
    Description

    Encrypts the credentials admins store in the admin, such as a payment provider's access data. The image leaves it empty, so every installation sets its own. Generate it once with openssl rand -base64 32 and never change it: credentials stored with another key, an empty one included, can't be read anymore, and admins have to enter them again.

  • Name
    DATABASE_URL
    Type
    URL
    Description

    The MariaDB database, e.g. mysql://fepli:secret@mariadb:3306/fepli. URL-encode special characters in the password (@ becomes %40).

  • Name
    DATABASE_SERVER_VERSION
    Type
    string
    Description

    The version of your MariaDB server, e.g. mariadb-12.3.0. It has to match the server you run, or the database layer generates SQL for the wrong version. The default is mariadb-11.2.4.

  • Name
    TRUSTED_HOSTS
    Type
    regex
    Description

    Every host fepli answers on, as one regular expression, e.g. ^(www\.)?example\.fepli\.eu$. With several tenants, join their hosts with |, and add the platform console. Production must set it: fepli builds the links in its e-mails from the host a request names, and an empty value accepts every host.

  • Name
    APP_BASE_URL
    Type
    URL
    Description

    Scheme and fallback host for links in e-mails, e.g. https://example.fepli.eu. Links in e-mails go to the domains of the tenant they are about, wherever the e-mail was sent from, as described under Domains. A link gets the scheme and host of APP_BASE_URL only where fepli knows no tenant for it, or the tenant has no domain for it.

  • Name
    MAILER_DSN
    Type
    DSN
    Description

    The outgoing mail server, e.g. smtp://user:password@smtp.example.org:587. Use smtps:// for port 465. The image has no local mail server, so the default doesn't work.

  • Name
    ADMIN_EMAIL
    Type
    email
    Description

    The envelope sender of every e-mail, which is where bounces go, and the address of the CMS, e.g. ferienpass@example.fepli.eu. Your mail server has to be allowed to send for its domain (SPF, DKIM). The image sets none: without it, e-mails have no envelope sender of their own, and bounces go to the address they were sent from. Each tenant sets the sender name and reply address its families see in its own admin.

Services

How fepli reaches Redis and, if you run it, Varnish. Redis is used for four things, each in a database index of its own. The values below assume the services are called redis and varnish, as in the examples.

VariableExampleWhat it is for
REDIS_URLredis://redis:6379/1the cache of the tenants' settings
LOCK_DSNredis://redis:6379/2locks, e.g. so two families can't book the last place at the same moment. The default, flock, only works within one container.
SESSION_DSNredis://redis:6379/3the sessions of everyone signed in. Empty keeps them in files inside the web container: that serves one web container only, and an update signs everyone out. Set Redis to keep sessions across updates and to run more than one web container.
MESSENGER_TRANSPORT_DSNredis://redis:6379/messagesthe queue of background jobs, read by the worker. The database index goes into the query string (?dbindex=0), not into the path.
VARNISH_HOSTvarnish:80where fepli sends purge requests when data changes. Set it empty to run without Varnish: fepli then sends none. The default is varnish:80, so leaving it out is not the same as setting it empty.
VARNISH_BASE_URLhttp://varnishthe base URL of those requests. This is the default. Without Varnish it doesn't matter.
VARNISH_PURGE_TOKENthe output of openssl rand -hex 32optional: the secret Varnish and fepli share for purges. fepli sends it with every purge request, in the header X-Purge-Token. With a value in its own environment, Varnish accepts purges only from the private network and only with that value; without one, any request from the private network may purge. So give Varnish and the web, worker and cron containers the same value. With the token on Varnish alone, every purge fails with 405.

Redis must keep its data on disk and must never evict keys: an evicted job is an e-mail that never goes out, an evicted session is someone signed out in the middle of applying. Start it with --appendonly yes --maxmemory-policy noeviction.

Trusted proxies

  • Name
    TRUSTED_PROXIES
    Type
    string
    Description

    The addresses the proxies in front of fepli connect from, Varnish and your TLS proxy, as a comma-separated list of addresses and ranges. fepli takes the visitor's address from X-Forwarded-For and the scheme from X-Forwarded-Proto only in requests from these addresses. The default, 127.0.0.1,::1,172.16.0.0/12,192.168.0.0/16, covers the networks Docker gives a Compose project. Set it where your proxies connect from elsewhere, e.g. 10.0.0.0/8 on Docker Swarm or Kubernetes. Empty trusts no proxy.

Multi-tenant installations

  • Name
    FERIENPASS_PLATFORM_HOST
    Type
    host
    Description

    The domain of the platform console, e.g. platform.example.fepli.eu. Leave it unset on a single-tenant installation. Add the domain to TRUSTED_HOSTS as well.

Object storage

fepli keeps what people upload and what it exports on the local disk, in the storage volume. Name a bucket in S3-compatible object storage, and that part moves there instead. Without these variables, or with them empty, everything stays on the disk: an installation without object storage needs no configuration for it.

  • Name
    S3_FILES_BUCKET
    Type
    string
    Description

    The bucket for files that are kept: attachments, and each tenant's logo and sign-in picture. Include it in your backups.

  • Name
    S3_EXPORTS_BUCKET
    Type
    string
    Description

    The bucket for exports and the files attached to a Rundmail. fepli deletes Rundmail files after 7 days and builds an export again when it is missing, so give the bucket a rule that expires objects after 7 days or more.

  • Name
    AWS_S3_ENDPOINT
    Type
    URL
    Description

    The URL of your object storage, e.g. https://s3.example.fepli.eu.

  • Name
    AWS_S3_REGION
    Type
    string
    Description

    Its region.

  • Name
    AWS_S3_ACCESS_ID
    Type
    string
    Description

    With AWS_S3_ACCESS_SECRET, a key that may read, write and delete in both buckets.

Each bucket variable decides on its own: with only S3_FILES_BUCKET set, exports stay on the disk. What goes where:

WhatBucketKeys
attachments of offersfilesattachments/…
attachments of e-mail replies, files families send with an applicationfilesinbound_attachments/…
a tenant's logo and sign-in picturefilesbranding/<tenant>/…
exports, files attached to a Rundmailexportsat the root
images of offers, organisers' logosnonealways on the disk: fepli resizes images from local files only

On a multi-tenant installation, <tenant> is the tenant's UUID, so each tenant's logo and picture have a folder of their own. A single-tenant installation uses default. The other keys are not split by tenant: which file belongs to which tenant is kept in the database.

Naming a bucket doesn't move the files already on the disk. Copy them first, each directory under storage/ to its keys in the table (storage/attachments/ to attachments/ in the files bucket, storage/export/ to the root of the exports bucket), and set the variable afterwards: fepli looks for a file only where its variable points.

Optional

Features that are off until you set their variable. Keys set here apply to every tenant; for several of them, admins can also store their own in the admin, per tenant, under Einstellungen → Integrationen. A key set here wins over the one in the admin.

VariableSwitches on
MAPBOX_TOKENmaps: the meeting point on an offer's page, the location picker in the admin
PMPAYMENT_AGS, PMPAYMENT_PROCEDURE, PMPAYMENT_SALTonline payment through pmPayment, with one account for the whole installation
BREVO_API_KEY, BREVO_DSNtext messages through Brevo. BREVO_API_KEY also registers the webhook for delivery reports.
INBOUND_SECRET, INBOUND_DOMAINe-mail replies: replies to a message from the admin arrive in its conversation. INBOUND_DOMAIN only on a single-tenant installation; with tenants, each names its reply domain in the admin.
OPENAI_API_KEYthe AI features of the admin, such as generating offer images
DEEPL_API_KEYmachine translation through DeepL
CORS_ALLOW_ORIGINcalls to the REST API from other websites' browsers, as a regular expression of their origins. By default only localhost may.
STATUS_HEARTBEAT_URLan hourly request from the cron to this URL, for an uptime monitor that raises an alarm when the cron stops
SENTRY_DSNerror reports to your own Sentry project. Without it, fepli sends none.

Tuning

VariableDefaultWhat it does
FRANKENPHP_MAX_THREADS6how many requests one web container handles at the same time. Each can take up to 512 MB of memory.
PORT80the port the web container listens on
MIGRATE_ON_START1whether the web container migrates the database when it starts. Set 0 to run app:migrate yourself.
RELYING_PARTY_NAMEfeplithe name browsers show when an admin creates a passkey

Set by the image

Leave APP_ENV=prod and APP_DEBUG=0 as the image sets them. Debug mode shows internals to every visitor.

The worker gets one variable more than the others: IS_WORKER=1.

A complete example

fepli.env

# openssl rand -hex 32
APP_SECRET=9f1c…
# openssl rand -base64 32, and never change it
INTEGRATIONS_ENCRYPTION_KEY=Qm3v…

DATABASE_URL=mysql://fepli:secret@mariadb:3306/fepli
DATABASE_SERVER_VERSION=mariadb-12.3.0

REDIS_URL=redis://redis:6379/1
LOCK_DSN=redis://redis:6379/2
SESSION_DSN=redis://redis:6379/3
MESSENGER_TRANSPORT_DSN=redis://redis:6379/messages

# With Varnish. Without it: VARNISH_HOST=
VARNISH_HOST=varnish:80
VARNISH_BASE_URL=http://varnish
# openssl rand -hex 32; Varnish gets the same value
VARNISH_PURGE_TOKEN=5b0e…

# Only where your proxies connect from outside Docker's Compose networks
#TRUSTED_PROXIES=10.0.0.0/8

TRUSTED_HOSTS='^(www\.)?example\.fepli\.eu$'
APP_BASE_URL=https://example.fepli.eu

MAILER_DSN=smtp://ferienpass%40example.fepli.eu:secret@smtp.example.fepli.eu:587
ADMIN_EMAIL=ferienpass@example.fepli.eu

# Only with object storage. Without it, uploads stay in the storage volume
#S3_FILES_BUCKET=fepli-files
#S3_EXPORTS_BUCKET=fepli-exports
#AWS_S3_ENDPOINT=https://s3.example.fepli.eu
#AWS_S3_REGION=eu-central
#AWS_S3_ACCESS_ID=…
#AWS_S3_ACCESS_SECRET=…

Docker Compose reads such a file with env_file:. Put regular expressions in single quotes, so that Compose leaves the $ and the backslashes in them alone. The file holds the secrets: make it readable only for yourself (chmod 600).

Was this page helpful?