Skip to content

First deploy of a Gisila app

In this guide you deploy a Gisila API from a git repository. At the end it runs as a sandboxed systemd service, passes the panel’s health check, and answers on your own domain over HTTPS.

  • A panel you can sign in to with at least the developer role in a team (Install on a VPS).
  • The Dart runtime installed on the Applications page (a superuser does this once per server).
  • A Gisila app in a git repository with a bin/server.dart entry point. The server must be reachable from the panel: public over https://, or private with an SSH deploy key (see Deploy from git, a binary or a ZIP).

1. Make the app read PORT and expose a health check

Section titled “1. Make the app read PORT and expose a health check”

The panel tells your process which port to listen on through the PORT env var. A health check path lets the panel confirm after each deploy that the app actually routes requests, not only that the process started.

bin/server.dart
import 'dart:io';
import 'package:gisila/gisila.dart';
Future<void> main() async {
final port = int.parse(Platform.environment['PORT'] ?? '8080');
final app = GisilaApp(
config: AppConfig(
// Answers {"status":"ok"} with no auth, ahead of other middleware.
healthCheckPath: '/healthz',
),
);
// ...register services and controllers...
// stopOnSignals: drain requests on the SIGTERM systemd sends on restart.
await app.start(host: '127.0.0.1', port: port, stopOnSignals: true);
}

Commit and push.

In the UI, open a team, create a project, then New app. Or use the API (see Use the API with tokens):

Terminal window
H='Authorization: Bearer gsl_xxxxxxxxxxxxxxxx'
J='Content-Type: application/json'
PANEL=https://panel.example.com
curl -sX POST $PANEL/projects/ -H "$H" -H "$J" \
-d '{"teamId": 7, "name": "Billing"}'
curl -sX POST $PANEL/apps/ -H "$H" -H "$J" -d '{
"projectId": 12,
"name": "billing-api",
"runtime": "dart",
"sourceType": "git",
"gitUrl": "https://github.com/acme/billing-api.git",
"gitBranch": "main",
"internalPort": 4001,
"healthCheckPath": "/healthz",
"memoryMbLimit": 256,
"cpuQuotaPercent": 50
}'

runtime picks the installed Application by key. You can pass its numeric applicationId instead. With no buildCommand, the Dart runtime runs dart pub get && dart compile exe bin/server.dart -o build/app, and the binary becomes <workDir>/current/app. Pin a toolchain with dartVersion if you have several installed.

internalPort must be between 1024 and 65535 and not used by another app.

Add configuration before the first deploy, since env vars are read at build and at start:

Terminal window
curl -sX POST $PANEL/apps/42/envs -H "$H" -H "$J" \
-d '{"name": "DATABASE_URL", "value": "postgresql://…", "isSecret": true}'

See Env vars and secrets.

Click Deploy, or:

Terminal window
curl -sX POST $PANEL/apps/42/deployments/ -H "$H" -H "$J" \
-d '{"sourceType": "git"}'
# → {"id": 101, "status": "queued", ...}

The Build logs tab streams the clone, the compile, unit generation, the restart, and finally the health check:

Verifying the service is up…
Deployment succeeded. gisila-app_ab12cd.service is active, 127.0.0.1:4001 is
accepting connections, /healthz answered, and stayed that way for 5s after the
restart.

Point an A record for api.example.com at the server, then add the domain and issue a certificate from the Domains tab, or:

Terminal window
curl -sX POST $PANEL/apps/42/domains/ -H "$H" -H "$J" \
-d '{"hostname": "api.example.com", "isPrimary": true}'
curl -sX POST $PANEL/apps/42/domains/<domainId>/ssl -H "$H"
Terminal window
curl -s https://api.example.com/healthz
# {"status":"ok"}
curl -s "$PANEL/apps/42" -H "$H" | jq .status
# "running"

If the deploy fails, the end of the build log shows why (nothing listening on the port, /healthz failing, or the unit crash-looping) followed by the last journal lines of the unit.