Sthora
Getting started

Deploy your first application

From an empty portal to a running application on your own hostname, in the order that works.

This walks through a ZIP upload, which needs nothing connected anywhere. Deploying from Git is two more steps and is what you will use afterwards.

1. Create a project

A project is a name and a slug. It comes with one environment, production. Environments exist so the same application can have a staging copy without a second project.

2. Add an application

An application belongs to an environment and lives on one server. You name it and tell it which port your container listens on — that is the one value the platform cannot work out for itself, and it is what the health gate connects to and what the router forwards to.

Optional at creation, changeable later:

SettingDefaultWhat it does
Exposed service nameDetectedWhich service in a multi-service compose file is the one facing the world.
Compose path / Dockerfile pathDetectedWhere to look, if the file is not at the source root.
Context pathSource rootThe build context.
Health timeout60 secondsHow long the health gate waits before failing the deployment.
CPU limitNoneWritten into the rendered compose file as cpus.
Memory limitNoneWritten as mem_limit.
Image retention3How many previous images to keep. Each one is what a rollback re-applies.
Deploy strategyRECREATESee deployments and rollback.

3. Upload a ZIP

Zip your source and upload it. The platform looks for compose.yaml, compose.yml, docker-compose.yaml, or docker-compose.yml first, then a Dockerfile, and — if Nixpacks is enabled and the tree carries a recognised manifest — builds it with Nixpacks. If none of those apply it fails with a message naming both options.

The upload cap is 200 MB, and the archive is refused whole rather than partially extracted if it exceeds that, 20,000 entries, or 2 GB extracted. Any entry whose resolved path escapes the destination rejects the entire archive.

4. Watch the build

The build streams live. Every line of docker compose build output reaches the portal as it happens, and lands in a size-capped log file on the server. Values of your environment variables are scrubbed out at the single point every line passes through.

When the build finishes, the platform brings the containers up and health-gates them: your container's own HEALTHCHECK if it declares one, otherwise a TCP connect to the port you named, retried with backoff until the health timeout.

Until you attach a hostname, the application is published on a numbered port on the server — shown on the application's page — so you can reach it immediately.

5. Put it on a domain

This order is not ceremony, and doing it out of order costs you an hour.

Add the hostname on the application. The portal shows the exact A record to create.

Create that record at your DNS provider, and wait for it to propagate.

Press Check DNS. Only once the hostname resolves to this server does a router get attached and a certificate get requested.

Why the order matters

Attaching a router before DNS resolves makes Traefik ask Let's Encrypt for a certificate it cannot validate. Production allows five such failures per hostname per hour — get it wrong and you are locked out of your own certificate for an hour. Develop against PROXY_ACME_STAGING=true, whose limits are far looser and whose certificates browsers do not trust.

Once a hostname is attached, the application stops being published to the internet on a numbered port. It keeps a loopback-only binding on the server so the platform can still health-check it.

What you have now

A running application, on your own domain, with a certificate that renews itself. From here:

On this page