Skip to content

Addons

An addon brings a service into your projects that Envoryx doesn’t ship itself: phpMyAdmin next to the database, an Elasticsearch for an app that insists on it, a Keycloak to try single sign-on against. A short YAML file describes one container per project, and once an admin has installed that file, every project can add the service from its Services section. No new Envoryx version needed.

Redis, Mailpit, the search engines, Ollama and object storage stay built in, because they come with extras an addon can’t offer (the Mailpit inbox, model downloads, bucket policies). Addons sit next to them.

Addon files live in /config/addons/<name>.yml, and you manage them under Settings → Addons, which takes an admin. There are three ways in:

  • Examples lists five files that come with Envoryx. Install one as it is or adjust it first.
  • New addon opens an editor with a starting file, and Edit changes one you installed.
  • Install from a URL fetches a file over http(s), a raw GitHub link for example.

The examples cover what people ask for most. phpMyAdmin opens already signed in to the project’s MySQL or MariaDB database. pgAdmin is the PostgreSQL counterpart in desktop mode, without a login; its card shows the database’s host, user and password so you can add it as a server. Elasticsearch 9 or 8 runs one node without security and can publish its port for desktop clients. Soketi is a Pusher-compatible WebSocket server for Laravel Echo and broadcasting, and browsers reach it through its web UI address. Keycloak 26 runs in development mode with an admin password generated per project.

Envoryx checks every file when you save it: an unknown key, a name it uses itself, an image that isn’t a valid reference or a placeholder the addon can’t fill is refused, with the reason. A file in /config/addons that doesn’t parse shows up in the list with its error, so a typo made over SSH doesn’t disappear silently. A file can be up to 64 KB.

Installed addons appear at the bottom of the project’s Services section as Add phpMyAdmin and so on, with a version to pick and, when the addon offers it, Publish the port on the host. Developers can add, change and remove addons in their projects; only installing the files is an admin’s job.

Adding one creates its container on the project network. If the addon hands variables to your application, the application containers are recreated with them. The card then shows the web UI’s address, the host and port inside the project, the host port, the volumes, the image, the credentials worth knowing and the variables your application gets under Injected.

An addon never overrides a variable that’s already taken. Envoryx’s own (DB_HOST, ENVORYX_URL and the rest) and the project’s own variables always win, and if two addons inject the same name, the first one keeps it. The card lists what didn’t make it under Not injected, so you can see at a glance that an addon’s DB_HOST isn’t what your application uses.

An addon with a web UI gets its own address through the proxy, https://<project>-<addon>.<base domain> (for shop and phpMyAdmin that’s https://shop-phpmyadmin.test), and a host port as well, like Mailpit.

Removing an addon from a project deletes its container. If it keeps data in volumes, you confirm by typing the addon’s name, and the volumes go too.

The examples are the best starting point, since they’re real files that work. Here’s phpMyAdmin:

/config/addons/phpmyadmin.yml
name: phpmyadmin
title: phpMyAdmin
description: Web UI for MySQL and MariaDB, signed in to the project database.
homepage: https://www.phpmyadmin.net
versions:
- version: "5.2"
image: phpmyadmin:5.2
default: true
port: 80
webUI: true
env:
PMA_HOST: "{{database.host}}"
PMA_PORT: "{{database.port}}"
PMA_USER: "{{database.user}}"
PMA_PASSWORD: "{{database.password}}"
UPLOAD_LIMIT: 512M

These are all the keys a file can have:

Key What it does
name 2-30 lower-case letters, digits and dashes; the container is envoryx-<project>-addon-<name>. It can’t be a name Envoryx uses itself.
title, description, homepage What the UI shows. title defaults to the name.
versions At least one, each with version and image. default: true marks the one a project gets when it doesn’t pick, otherwise it’s the first.
hostname The name on the project network, the addon’s name unless you set one.
port What the container listens on: {{port}}, the web UI and the host port use it.
webUI true gives the addon its own address through the proxy.
publishPort true offers Publish the port on the host, for desktop clients.
command Replaces the image’s command, as a list.
user The user inside the container, like "1000:1000".
env The container’s own environment. Names may contain lower-case letters and dots, for images that read their settings that way (discovery.type: single-node).
secrets Names of secrets: 24 random characters per project, used as {{secret.<name>}}.
volumes Named volumes with name and path; noBackup: true keeps one out of backups.
healthcheck test like in Docker, plus interval, timeout, startPeriod (up to 1h each) and retries.
inject Variables handed to your application containers. Regular variable names only ([A-Z_][A-Z0-9_]*).
credentials What the card shows, each with label and value; secret: true masks it until you reveal it.

The values can use placeholders: {{host}} and {{port}} (the addon inside the project network), {{url}} (the web UI’s address, empty without webUI), {{project.slug}}, {{project.name}}, {{project.url}}, the project’s primary database as {{database.type}}, {{database.host}}, {{database.port}}, {{database.name}}, {{database.user}} and {{database.password}} (empty when the project has none), and {{secret.<name>}} for each secret you declared. So an addon that wants a password of its own and tells your application where it lives looks like this:

secrets: [password]
env:
WIDGET_PASSWORD: "{{secret.password}}"
inject:
WIDGET_URL: "http://{{host}}:{{port}}"
credentials:
- {label: Password, value: "{{secret.password}}", secret: true}

Viewers don’t get the value of a secret credential at all.

What a file can’t do is just as deliberate. There’s no field for privileged mode, capabilities, host directories, the host network or devices, and unknown keys are errors. An addon always runs with named volumes on its project’s network, like the built-in services, so installing one from a URL can’t hand a container your host.

Each project keeps a copy of the definition it runs, together with its generated secrets. When you save a new version of an installed file, that copy is updated in every project that uses the addon. New secrets are generated, existing ones stay, and a version the file no longer lists falls back to the default. The containers follow at the project’s next start or restart: the addon’s own, and the application containers too if the injected variables changed.

A file that a project still uses can’t be deleted; Envoryx tells you which projects. If the file disappears anyway, say someone removed it from /config/addons by hand, the project keeps running its copy but can’t change it any more.

A database backup, manual, scheduled or the one before an upgrade, also archives every addon volume that isn’t marked noBackup, as addon-<name>-<volume>.tar.gz. The addon’s container is stopped while its volumes are read, so the archive is consistent, and started again afterwards. Restoring the database part of a backup empties those volumes and unpacks the archives, for the addons the project still has. A snapshot of a single database leaves the addon volumes out.

A duplicate gets the same addons with secrets of its own, new host ports and empty volumes. Renaming a project moves the volumes along.

In envoryx.yml the project’s addons go under addons:. The server you apply the file to needs the addon file installed:

addons:
phpmyadmin: true # the default version
elasticsearch: {version: "8", exposePort: true}

envoryx up --prune removes an addon the file no longer names, together with its volumes.

On a managed instance the hoster’s plan can leave addons out, and then they aren’t available on that instance.