Docker image
Mode 1A public image, or one from a private registry whose credentials live in Settings. An image reference and an internal port is the whole form.
Reference
Quasar is small on purpose, which makes this list finite. It is the whole of it — not the highlights.
Getting code onto the box.
Three ways in, and a set of behaviours designed so that the file already in your repo is the file that runs.
A public image, or one from a private registry whose credentials live in Settings. An image reference and an internal port is the whole form.
A repository carrying a docker-compose.yml or a Dockerfile. Quasar clones it, works out which one describes the application, and builds. Private repositories authenticate with a scoped token.
Paste a compose file directly. Quasar stores it under the app and runs the stack from there.
A repo with a compose file at its root is deployed as a stack — a Dockerfile next to it usually describes one service of that stack, not the whole app. The app's page states what was detected and lets you override it when the compose file exists only for local development.
Host publications of ports 80 and 443 are dropped — Traefik owns those for the entire server — the front service is joined to traefik-net, and the router labels are written onto it. The result goes to a generated docker-compose.quasar.yml beside the original, on every deploy. Your repository is never modified. A file that already carries traefik.* labels is run untouched.
No service name and no image name is ever consulted. In order: whichever service published host port 80/443; else the one the rest of the stack lines up behind through depends_on; else the only one offering the app's configured port; else the only service in the file. If nothing resolves, Quasar changes nothing rather than routing your domain at random, and the Routing panel asks. YAML anchors and merge keys are flattened first, or the labels would land on a shared anchor.
Redeploy recreates the container from what is already on the server — same image, same commit — which is what applies a configuration change. Update fetches first: git pull and rebuild, docker pull, or docker compose pull.
A secret URL per app. A push from GitHub or GitLab triggers pull, rebuild and redeploy — the same path as Update.
Every deployment recorded with its source, image, duration and outcome. The last four built images per app are kept, so rolling back is one click rather than a rebuild.
Prefilled forms with generated secrets for PostgreSQL, MySQL, Redis, Uptime Kuma, Ghost, n8n, Vaultwarden.
Each token declares a scope — a forge (github.com), an organisation (github.com/acme), one repository, or * as a fallback — and the narrowest match wins. Comparison is segment by segment, so github.com/acme never matches github.com/acmecorp. A personal account and a work organisation keep separate tokens and are never offered each other's.
Registry logins stored for private image pulls, alongside the Git tokens and under the same encryption.
Names, certificates, and why one is missing.
A subdomain and an internal port is the entire routing configuration. The interesting part is what happens when it does not work.
Subdomain plus internal port becomes a generated set of Traefik labels. The certificate is issued by Let's Encrypt on the first request that arrives for the name.
Any app can answer for extra hostnames — www.myblog.com alongside its own subdomain — each with its own certificate.
Every hostname an app serves reports its certificate state, and when one is missing the page says why: the name does not resolve, or it resolves somewhere other than this server. That second case — a registrar's leftover A record still pointing at shared hosting — is the usual reason an app has no HTTPS while everything looks correct.
Every certificate Traefik holds, listed next to the app that routes it. Ones nothing routes any more can be deleted; Traefik restarts, which costs a few seconds of downtime.
The knobs each app gets.
An editor in the dashboard. Values are written to the database and to apps/<id>/.env, which is passed to compose stacks as --env-file.
A container path mounted onto apps/<id>/data/ on the host, so state survives every redeploy.
Maximum CPU and memory per application, enforced through cgroups.
Traefik basic auth, switchable per app, applied at the proxy rather than in your application.
Start, stop, restart, redeploy, rollback and delete.
Finding out what is going on.
The half of hosting you actually spend time in.
Streamed over server-sent events, with ANSI colours preserved and severity inferred for lines that bring none of their own. The pane follows the tail.
Search across applications from one page rather than opening each container in turn.
CPU, memory and disk gauges for the host, plus per-container statistics. A background watcher tracks state so an app that fell over is marked without you refreshing.
CPU and memory samples — server-wide and per app — stored in SQLite and drawn as 24-hour SVG sparklines rendered on the server.
A periodic probe per app, automatic restart after three consecutive failures, and an availability history kept afterwards.
A Discord- and Slack-compatible webhook for failed deployments, apps entering an error state, recoveries, and failed backups.
Host hardware, the platform's own containers, Docker disk usage and per-app size — the view you open when something is wrong with the box rather than with an app.
When you need to reach inside.
A real interactive shell inside the container — xterm.js over a WebSocket. No SSH hop and no docker exec typed by hand.
Commands executed inside a container through docker exec, on demand or on a fixed interval. Output and exit status are kept between runs.
Keeping the disk and the database in hand.
On demand or nightly. Each archive holds a consistent SQLite snapshot plus every app's data/ and .env. Retention is configurable and archives download from the dashboard.
One click from the System page: SQLite tables are re-attached, data/ and .env are put back. Redeploy afterwards.
Docker usage broken out by images, containers, volumes and build cache, with size per app. The sweep prices every category before you press it, then removes what nothing claims: untagged layers, images with no container, build cache, containers a deploy left behind, empty networks. Stopped apps, their images and each app's recent git builds — the rollback targets — are spared. Orphaned volumes are offered separately, behind a checkbox, because those do not come back with a pull.
What it is careful about.
The dashboard reaches Docker only through tecnativa/docker-socket-proxy, restricted to the API sections it needs: containers, images, networks, build, session, grpc, volumes, info, system, exec, and POST. EXEC=1 exists for the web terminal and tasks — drop it if you use neither. SESSION=1 and GRPC=1 give access to the daemon's BuildKit; without them docker compose build starts a privileged BuildKit container per build instead.
Admin and viewer. A viewer sees every application, log, metric and audit entry and can change nothing. The last admin account cannot be demoted or deleted.
TOTP, enrolled by QR code, required at login once enabled.
Bearer tokens carrying a role of their own, for driving the platform from CI. A viewer token reads apps and host metrics; an admin token deploys and restarts.
Who did what, to what, and from which address — searchable by user, action or target, and never rewritten.
HTTP-only, Secure, SameSite=Lax session cookies; bcrypt password hashing; active sessions listed and revocable.
The host's / is mounted read-only into the dashboard, and only so that disk metrics have something to measure.
Looking after Quasar.
GitHub releases are checked every six hours and installed in one click through an ephemeral updater container. Only the dashboard is unavailable, for a few seconds. Your applications are not touched.
Nebula (dark, default), Marathon, Nord, Synthwave, Terminal, Paper and Solarized. Implemented as CSS custom properties and persisted in a cookie — the switch in this page's footer is the same mechanism.
Ten minutes on a 1 GB box, and you can delete it just as fast if it is not for you.
curl -sSL https://raw.githubusercontent.com/AymericChaverot/quasar/main/setup.sh | sudo bash