All documentation
  1. Home
  2. Docs
  3. Applications

Applications

An application is one or more container images, a private network, storage with a fixed size, and a domain with a certificate. KLYRN owns all of it: there is no Docker socket to reach, no privileged mode to ask for, and no host network to join.

What an application is

A site is a domain served by nginx from a directory. An application is a domain served by nginx from a container. Everything else KLYRN does (accounts, certificates, backups, jobs, resource limits, the reseller model) works the same way on both.

Service
One image, running. An application may have several; they see each other by name on a network only they share.
Route
A domain, a service and a port inside that service. nginx and the certificate are KLYRN's, exactly as for a site.
Volume
Storage that survives redeployment. Its own filesystem with its own fixed size.
Release
One deployment, recorded with the image digest it actually ran, so a rollback is exact rather than approximate.

Node.js applications are a different thing with a different lifecycle and are documented under Node.js. They are klyrn app; these are klyrn container.

Creating and deploying

klyrn container list
klyrn container show shop
klyrn container deploy shop --image ghcr.io/you/shop:2.1
klyrn container route add shop shop.example.com --port 8080
klyrn container logs shop --tail 200 --search error

A deployment pulls the image, starts the new container and waits for it to answer. If it never answers, the deployment fails and the previous release is put back: the end state is the release that was serving before.

The new container binds the public port before its health check runs. So between it starting and the check failing, your domain serves a release that never passed, measured on a real deployment at 323 of 347 samples over 90.5 seconds. KLYRN used to claim the opposite; the claim is withdrawn, and a failed deployment now reports how long its window was. Closing it needs the new container on a port of its own with nginx moving to it only after the check passes, and that is not in 0.3.5‑beta.1. Deploy behind a maintenance window if it matters to you. The full entry.

Every release records the digest it ran, not the tag. A tag moves; a digest does not. That is why a rollback puts back what was actually serving:

klyrn container releases shop
klyrn container rollback shop 7

A Docker Compose file can be imported from the panel. Fields that would take a container off its leash are refused by name, with the reason. See what is refused.

What is enforced, and by what

This distinction is the whole point, and it is worth more than a list of features. A control the kernel applies is a different kind of thing from one a daemon reports.

PropertyEnforced by
A volume cannot exceed its sizeext4 on its own loop device. The write fails with ENOSPC; the server's free space does not move.
A container cannot write to its root filesystemReadonlyRootfs, in the kernel. The write is refused.
Scratch space is boundedA tmpfs with a size, charged to the memory cgroup.
An account's memory and CPUIts cgroup slice.
A container cannot regain dropped privilegesno-new-privileges, plus every capability dropped.
A container's writable layerNothing. See below.

Why the root filesystem is read-only

Docker accepts a per-container storage limit and, with the overlay driver it installs by default, applies it to nothing. It is accepted at creation, accepted as a daemon default and accepted by the update endpoint: three separate places, each returning success, each enforcing nothing. A container can then fill the server's disk.

So KLYRN does not offer a writable-layer quota, because it could not keep one. It removes the writable layer instead: the root filesystem is read-only by default, scratch space is a tmpfs with a size, and anything that must survive goes in a volume. That is three controls the kernel actually applies, in place of one number that would have been a lie.

A service can be given a writable root deliberately. When it is, KLYRN says plainly that what it writes outside its volumes is limited only by the server's own free disk, and that the machine's disk reserve is not a limit on that application.

Volumes

A KLYRN volume is not a directory with a number written next to it. It is a sparse ext4 image on its own loop device: a real filesystem with a real size.

Default size
1 GiB. The largest is 1 TiB.
Filling it
Stops that application and nothing else. The write fails, the server's free space does not move, and no other customer notices.
Growing it
Online, from the panel. It never shrinks.
Backups
Included unless the volume is marked excluded.
Occupancy
Measured from the filesystem and shown as used-of-capacity, with the warning arriving before it matters rather than after.

An application will not start against an empty directory where its data should be. If a volume cannot be mounted the deployment is refused and no container is created, because a database that starts on an empty disk initialises a new one, and by the time anybody looks, the backup window has moved.

The server's own reserve

KLYRN keeps headroom on the host that applications may not allocate into: 10% of the disk, never less than 2 GiB and never more than 20 GiB. A volume that would eat into it is refused when it is asked for, which is a message. Running out of disk at three in the morning is an outage.

Isolation

Every application gets a private network. Its services reach each other by name on it, and nothing else is on it.

No Docker socket
Mounting /var/run/docker.sock (or containerd's, or CRI-O's, or Podman's) is refused. A container that can talk to the daemon can start a privileged one, and is therefore root on the server.
No privileged mode
Refused. A privileged container holds every capability and every host device: it is a root process with a different filesystem, not a container.
No host networking
Refused. It would put the container on the server's own network stack, where it could bind the server's ports and reach anything listening on 127.0.0.1 (including the database and the panel) unfiltered by the firewall.
No host paths
A container mounts KLYRN volumes, and nothing else off the host.
Capabilities
All dropped, always, with only a small reviewed set addable.
Registries
An allow-list: klyrn container registry list | allow | deny. Allowing one is an administrator's decision.

These are not settings that happen to have safe defaults. The validated type KLYRN deploys from has no field for privileged, network mode, devices, host ports or host mounts, so a future code path that forgets to check still cannot ask the daemon for one. The request type carries them only so they can be refused by name.

When something is refused

A refusal names the field, the value it held, and the reason. Most people who hit one copied a Compose file off the internet and have no idea what the field does, so the message explains it rather than saying the request was invalid.

The fix is almost always to delete the line. A container that wanted the Docker socket wanted to deploy things; a container that wanted host networking wanted a port. KLYRN gives it a route and a domain instead.

Environment and secrets

klyrn container env shop APP_ENV=production
klyrn container env shop --secret DATABASE_URL
klyrn container env shop --remove OLD_KEY

A secret's value is read from standard input, never from an argument. An argument is visible in ps to every user on the machine, and it lands in the shell history of whoever typed it.

Sealed values are stored sealed and unsealed at the last moment, by the deploy engine alone. They are not in the job log, not in a backup manifest, not in the panel and not in a support bundle.

Backups

klyrn container backup create shop
klyrn container backup list shop
klyrn container backup restore 128
klyrn container backup restore-as-new 128 --name shop-copy --domain copy.example.com
klyrn container backup schedule shop daily --keep 7

A backup holds the application's definition, the image digest each service ran, its routes, its limits, its environment including sealed secrets, and its volumes. It does not hold the image's layers: a restore pulls the recorded digest back from the registry.

It is enough to rebuild the application after it has been deleted, and it outlives the application on purpose.

Crash-consistent, and why we say so

A volume backup is crash-consistent. The filesystem is frozen and copied; nothing asks the application to flush first. A database restored from one recovers the way it recovers from a power cut: reliably, and not identically to a clean shutdown. Any other word would be the worst possible thing to be vague about, because the person reading it is deciding whether to trust a restore.

restore-as-new builds a second application beside the original from the same backup. It needs a domain of its own: reusing the original's would take the name away from the application that is currently serving it.

Restarts and reboots

Volumes are remounted and services brought back by KLYRN itself, ordered so that nothing starts against storage that is not there yet. This is tested by actually rebooting a server (with a volume 99% full and a WordPress site running beside the application) rather than by reasoning about unit ordering.

A service that has died says so. A container that is gone does not keep drawing a green dot because the page was last loaded while it was healthy.

What this server can run

klyrn container capabilities
klyrn containers status
klyrn containers preflight

capabilities answers whether this server can run an application at all and what it has left. preflight is the check the installer runs before enabling the runtime, and it can be run by hand at any time.

The container runtime is optional. A KLYRN server that hosts only websites never installs it, and enabling it later is one operation.

Building from a git repository

An application does not have to start from a published image. Give it a repository with a Dockerfile and KLYRN clones it, builds the image on this server, and deploys it, by the digest it built, never by a tag. Everything after the image is the same engine every other application uses: the network, the volumes, the environment, the health check, the domain, the certificate, backups, Move and rollback.

Applications → New application → Git repository

klyrn container source <name> [--repo URL] [--branch NAME] [--dockerfile PATH] [--context DIR]
klyrn container deploy <name>             # clone, build, deploy, health-check, keep or roll back
klyrn container releases <name>           # commit, branch, digest, how long the build took, what happened
klyrn container rollback <name> <release> # the image that release ran, started again; nothing is rebuilt

A build is treated as hostile code, because a Dockerfile is one. It runs with no Docker socket, no host network and no privileges, under a hard memory limit with no swap behind it, a CPU quota and a time limit, and it cannot fill the disk: it is held to the same storage reserve every website on the server depends on. The build context is confined to the repository: ../, absolute paths, symlinks that point out, devices and FIFOs are refused before a byte reaches the daemon.

Failure is kept honest. A build that fails says Build failed and production is unchanged; it never says a deployment failed when none started. A build that succeeds and then fails its health check leaves the previous release serving and says which of the two happened.

Private repositories use a deploy key KLYRN generates per application. The panel shows the public half to paste into the repository as a read-only key; the private half never leaves the server. A push can deploy automatically through a signed webhook whose secret is shown exactly once. Auto-deploy is off until you turn it on, so a repository never deploys before its environment is set.