Skip to content

Env vars and secrets

In this guide you configure an app with environment variables, mark the sensitive ones as secret, import a .env file, and apply the changes.

  • The developer role on the app’s team to change env vars. Any member can list them.
  • An API token for the scripted examples.
Terminal window
PANEL=https://panel.example.com
H='Authorization: Bearer gsl_xxxxxxxxxxxxxxxx'
J='Content-Type: application/json'
Terminal window
curl -sX POST $PANEL/apps/42/envs -H "$H" -H "$J" \
-d '{"name": "LOG_LEVEL", "value": "info"}'

POST /apps/{id}/envs is an upsert: setting an existing name overwrites it. Names must be plain identifiers (letters, digits, underscores), at most 200 characters.

Terminal window
curl -sX POST $PANEL/apps/42/envs -H "$H" -H "$J" \
-d '{"name": "STRIPE_KEY", "value": "<secret>", "isSecret": true}'

Secret values are never returned by the API again: GET /apps/{id}/envs lists them without value. To change only the flag, send the name and isSecret without value. The stored value is kept.

Every value, secret or not, is encrypted at rest in Postgres with /etc/gisila/secret.key. On the host it’s written to /srv/apps/<user>/.env (mode 0640, readable by the app’s user), never inlined into the world-readable unit file.

POST /apps/{id}/envs/bulk takes parsed entries and upserts each one. The UI parses a pasted .env file for you. From a script:

Terminal window
jq -Rn '[inputs | select(test("^[A-Za-z_][A-Za-z0-9_]*=")) | capture("^(?<name>[^=]+)=(?<value>.*)$")]
| {entries: map(. + {isSecret: false})}' < .env \
| curl -sX POST $PANEL/apps/42/envs/bulk -H "$H" -H "$J" -d @-
# → {"imported": 6}

Entries with an empty name are skipped. Variables not in the payload are left alone.

Env vars are written into the app’s .env file during a deployment. Saving a variable doesn’t restart the app, and a plain restart reuses the existing file. Redeploy for changes to take effect:

Terminal window
curl -sX POST $PANEL/apps/42/deployments/ -H "$H" -H "$J" -d '{"sourceType": "git"}'

For binary and zip apps, deploy the latest artifactId again.

Env vars are also available during the build, so steps such as database migrations in a build command see the same configuration as the running app.

Terminal window
ENV_ID=$(curl -s $PANEL/apps/42/envs -H "$H" | jq '.results[] | select(.name=="LOG_LEVEL") | .id')
curl -sX DELETE $PANEL/apps/42/envs/$ENV_ID -H "$H"

Then redeploy.

You don’t need to define these. See the App runtime contract for details.

Variable When
PORT Apps with an internal port (not static or process).
GISILA_APP_ID Always.
MEDIA_ROOT, MEDIA_URL When media storage is enabled, unless you set them yourself.
<PREFIX>_ENDPOINT, _REGION, _BUCKET, _ACCESS_KEY, _SECRET_KEY, _PUBLIC_URL, _FORCE_PATH_STYLE When a superuser links a storage bucket to the app.

Special variables you can set:

Variable Effect
GISILA_SYSCALL_FILTER=off Drops the seccomp syscall filter for this app on the next deploy. Use only if a runtime fails with EPERM.
FLOWER_BASIC_AUTH=user:password Celery apps: credentials for the Flower UI. Generated if unset.

From the app’s Console tab, or with the API:

Terminal window
EXEC=$(curl -sX POST $PANEL/apps/42/exec -H "$H" -H "$J" \
-d '{"command": "printenv LOG_LEVEL"}' | jq -r .execId)

The output streams on the /ws/apps/42/exec/$EXEC WebSocket (see View logs and metrics).