Skip to content

Configuration

Everything on this page can be changed after the application exists, and most of it without redeploying.

The panel and the CLI set the same fields. Add application and Edit open the same form — the one shown in the overview — and this is what each of its fields is called on the command line:

Field in the panelFlagExplained under
Namethe positional argumentSet once, at creation; it names the unit and the socket
Published on--domainWhere it is published
Path--pathWhere it is published
Start commandeverything after --The start command
Internal port--portThe internal port
Health path--healthThe health path
Linked directories--link, --clear-linksLinked directories
Memory (MB), CPU (%), Max tasks--mem, --cpu, --tasksResource limits

Two differences worth knowing before you use the form. Name is absent when editing, because it cannot be changed. And Linked directories is a single field of space-separated names, where the CLI repeats --link; clearing the field is what --clear-links does.

The program and its arguments go after a -- separator, as a path relative to the release root:

Terminal window
corepanel app create <account-id> api --domain example.com --port 8080 -- ./server --config prod.toml

The -- is what keeps your application’s flags from competing with the CLI’s, so --config above belongs to your program. The working directory is the release root — the current symlink, not the release it was deployed from, so a rollback changes what runs without rewriting the unit.

FlagMeaning
--domain <fqdn>The domain or subdomain of the account. A domain alias is refused: it has no site file of its own, so the route belongs on the domain it points at
--path </sub>/ for the whole site, or a path under it. A sub-path mount strips the prefix before the request reaches your program

Both can be changed later with update; the route is moved for you.

Terminal window
corepanel app update <account-id> api --domain app.example.com --path /
Terminal window
corepanel app create <account-id> api --domain example.com --port 8080 -- ./server

Your program listens on this port inside its own network namespace, where nothing else on the server can reach it. CorePanel exports it as $PORT, which nearly every framework reads without configuration.

It must be 1024–65535: the process runs unprivileged and without CAP_NET_BIND_SERVICE, so a lower port could never be bound. Two applications may use the same number without conflicting — the namespaces are separate — but keeping them distinct makes a ps listing easier to read.

Terminal window
corepanel app create <account-id> api --domain example.com --port 8080 --health /healthz -- ./server

After every deploy and rollback, CorePanel connects to the endpoint and — if a health path is set — requests it. Without one, the check only proves that something accepted the connection, which means bind succeeded and nothing more. A process that binds and then fails every request would pass.

The path is the one your program sees, after the prefix strip: an application mounted at /api with --health /healthz is checked at /healthz, and the visitor-facing URL is https://example.com/api/healthz.

Make it cheap. It runs on every deploy, and a health check that touches a database turns a slow database into a failed deploy.

The Environment card on the application lists every variable, with a pencil to change one and a bin to remove it:

The Environment card listing LOG_LEVEL with its value in clear and STRIPE_SECRET_KEY showing "Secret — never displayed back"

Add variable asks for three things — a name, a value, and whether it is a secret:

The Add variable dialog with a name, a value and a Secret toggle switched on, explaining that the application still receives it while the panel never shows it again

Turning Secret on is what makes the value unreadable afterwards, in the panel and the CLI alike. Editing one later opens with the value empty and says so: what is stored was never sent to your browser, and saving replaces it with whatever you type. Leaving the field blank therefore sets an empty value rather than keeping the old one.

The same, from corepanel:

Terminal window
corepanel app env list <account-id> api
corepanel app env set <account-id> api LOG_LEVEL=debug
corepanel app env set <account-id> api DATABASE_PASSWORD='...' --secret
corepanel app env unset <account-id> api LOG_LEVEL

The variables live in a file systemd reads as root before dropping privileges, so your application receives them while the account cannot read the file that holds them — not over FTP, not from a shell, not from the application itself.

A --secret value is never displayed back, in the panel or the CLI. It can be replaced, only not read. That is the point: the copy in CorePanel is not a place to look values up, it is a place to set them.

Setting or removing a variable restarts a running application, because a value stored but absent from the running process is the kind of half-applied setting that costs an afternoon to diagnose.

VariableValue
PORTThe internal port you chose
CP_APP_NAMEThe application’s slug
CP_APP_DATAThe persistent data directory
CP_APP_TMPA private /tmp, invisible to the rest of the server

Those four names are reserved; your own variables cannot override them. The panel refuses them in the editor rather than after a round trip, and applies the same rule to the name itself: it starts with a letter or _ and contains only letters, digits and _.

$CP_APP_DATA points at a directory that survives deploys, rollbacks and even deleting the application:

/var/opt/userapps/<account>/<app>/data

The program tree does not survive: every release replaces it. Anything your application must keep — uploads, a SQLite file, generated configuration — belongs under $CP_APP_DATA.

Some programs insist on writing inside their own tree and cannot be told otherwise. --link handles those: the named directory, relative to the release root, is replaced by a symlink into the data volume on every deploy.

Terminal window
corepanel app create <account-id> gitea --domain git.example.com --port 3000 \
--link data --link custom -- ./gitea web

./data then keeps its contents while everything around it is replaced. Repeat the flag per directory; corepanel app update ... --clear-links removes them all.

Every application has all three, and they are mandatory — an unbounded process on the same machine as the control panel is the straight road to an out-of-memory event that takes the panel down with it.

FlagDefaultMeaning
--mem <mb>256Hard memory ceiling. Exceeding it means the kernel kills the process; systemd restarts it
--cpu <pct>50Percentage of one core. 100 is a whole core, 200 is two
--tasks <n>64Threads and processes together
Terminal window
corepanel app update <account-id> api --mem 1024 --cpu 200

They are applied as cgroup properties, so they are enforced by the kernel rather than requested politely. If the application stops serving under the new settings, the previous ones are restored.

Sizing, roughly: a small Go or Rust API is comfortable at the defaults; a service with an embedded database, background jobs and a template cache wants 512–1024 MB and a full core; a program that spawns workers needs --tasks raised or it will fail to fork under load.

In the panel, Edit on the application opens the creation form again with the current values, minus the name. Only the fields you actually change are sent, so saving does not re-apply — or re-validate — settings nobody touched; if nothing changed, the form says so instead of writing.

Terminal window
corepanel app update <account-id> api --mem 512 --health /healthz -- ./server --addr :8080

Omitted fields are left as they are. The change is applied to the release already running — no redeploy — and if the application stops serving under the new settings, the previous ones are put back. An application that was stopped stays stopped.

Each account has a maximum number of applications, in parallel with its subdomain and addon-domain limits, and hosting packages carry it to the accounts they provision.

Zero means none here, not unlimited — this is the one limit in CorePanel that reads the other way round, and it has no unlimited value at all. An application is a resident program with its own memory, socket and network namespace, so an account gets to run them only when somebody grants a number: on the account (Edit account → Applications, or corepanel account update <id> --max-apps N) or on its hosting package.

Lowering the number below the applications already running is refused, exactly like any other limit below current usage; the applications themselves are never deleted to make room.

The complete list, with every default, lives in the CLI reference.