Clever CloudTutorialFor adminsApplies from 4.3.0
First deployment
Cette page en françaisThis page on the GitHub wiki
The first time the team Studio goes live: deploy the worker, then the studio, import the game once, invite the first owner, and check that the instance serves writes.
What you will build
A running hosted Studio at https://studio.example.fr: your game imported as revision 1, its files in the bucket, you
logged in as its first owner, and /readyz answering 200.
Verified on: 19 October 2026, by the reference deployment, from the repository, at engine commit 52e68932
(package.json 4.2.2, the 4.2.3 work before its tag), Clever Cloud test organisation, region par, two XS apps,
PostgreSQL DEV, Cellar S, managed Keycloak, on three *.cleverapps.io names. Not verified on a live installation:
this page's exact text, a custom domain, and the release-archive variant (below). Applies
from 4.3.0, the version whose packages carry the quest-n-click names used below.
What you need
- Apps and add-ons, Domains and TLS, the provider (Keycloak) and the Configuration, all done.
- Your game in the deployed repository, under
games/my-game(the configuration'sgame), with its prepared assets committed inpublic/. - The verified email you will log in with, known to the provider.
Steps
-
Deploy the worker first, then the studio, from your machine, in the engine repository:
# on your machine, in the engine repository clever deploy --alias my-game-worker clever deploy --alias my-game-studioEach deploy pushes the folder's current commit. The worker's build runs its Python hook; the studio's builds the Studio's page (
npm run studio-client). You see each end with "deployed".
-
Watch the studio start.
clever logsfollows the logs until it is stopped, even with--until: run it in the background, and stop it by its process id once you have what you need:# on your machine, in the engine repository clever logs --alias my-game-studio > studio.log 2>&1 & echo $! # the process id, to stop it later with: kill <that id>A refused configuration stops the server with one line naming the field (see Configuration). Once it listens and holds the lease, the log has a
{"event":"lease-taken",…}line.
-
Import the game once, from a shell on the studio app:
# on your machine, in the engine repository clever ssh --alias my-game-studio# in that shell, on the studio app cd "$APP_HOME" npm run studio-server -- import games/my-gameThe shell of
clever sshhas the app's variables (STUDIO_CONFIG_JSON, the add-ons'), so no command needs--config. The import sends every file to the bucket and prints{"event":"imported","game":"my-game","revision":1}. It refuses an instance that already has a project ("import: this instance already has a project").
-
In the same shell, invite the first owner:
# in that shell, on the studio app npm run studio-server -- invite --email you@example.fr --role ownerIt prints a one-time link,
https://studio.example.fr/auth/login?invite=…, valid 7 days. Open it and log in with that verified email. The invitation is consumed only by that email, verified by the provider.clever ssh --command '…'runs one command without an interactive session, but refuses while a second instance is listed (the old one of a deploy staysSTOPPINGfor about two minutes): wait for it to go.
-
Check the instance serves writes:
# on your machine curl -s https://studio.example.fr/readyzIt answers 200 with
{"ok":true,"writes":"served","rpoMs":0}once the instance holds the service lease, and 503 with"writes":"waiting"before. In the Studio,GET /auth/mesaysrole: owner; make one change (a note) and see it saved.
-
Take a first backup to the bucket, by the daily backup's own script, and see its line:
# in a shell on the studio app (clever ssh --alias my-game-studio) cd "$APP_HOME" && ops/studio/backup-cron.shIt prints
{"event":"backup","key":"backups/<date>-r1.json",…}(Backups).
From the release archives
From 4.2.1 a release carries quest-n-click-studio-server-<version>.tgz (named web-scumm-studio-server-… before
4.3.0): the two commands quest-n-click-studio-server and quest-n-click-studio-worker, the Studio's page already
built, and its own dependencies (OpenID Connect, JWT, Postgres). Their versions are locked in its
npm-shrinkwrap.json and its SBOM. npm reads that lock when it installs from the registry, not from an archive file,
where pg takes the latest 8.x its range allows (quest-n-click-studio-server deps says which). It runs the server of
the engine installed beside it, which must be the same version:
# in your deployment folder (an app's repository or a server), the two archives of one release beside it
npm install quest-n-click-<version>.tgz quest-n-click-studio-server-<version>.tgz
npx quest-n-click-studio-server import ./my-game --config studio.config.json
npx quest-n-click-studio-server serve --config studio.config.json
npx quest-n-click-studio-worker # on the worker's machine, with WORKER_PUBLIC_KEY and WORKER_INSTANCE- A worker installed from the archives prepares assets too (since 4.2.3; in 4.2.2 this needed a worker deployed from
the repository). Its build hook installs the lock the engine's package carries, from the worker's folder, where the
worker looks for the packages (
WORKER_PYTHON_PATHto put them elsewhere):CC_POST_BUILD_HOOK=python3 -m pip install --target .python --require-hashes --only-binary=:all: -r node_modules/quest-n-click/ops/studio/worker-requirements.lock. The lock is for CPython 3.13 on Linux x86_64 with glibc 2.28 or newer (Clever Cloud's native runtime); on another platform, make it again (its header says how). - The engine's archive brings Vite and tsx, which the worker needs to run the game's code and build its previews (the Studio itself no longer runs Vite, since 4.2.2).
- Set
publicDirto your game's prepared assets (public/of your game's repository): the engine's ownpublic/holds only its icons and font. - The archives do not carry the daily backup's script: Backups says how to add it.
- Each release's candidate installs these two archives in an empty folder and serves a game from them, its
dependencies found whether npm hoists or nests them (
scripts/studio-install-smoke.mjs). That is a CI check, not a Clever Cloud deployment.
The general install from the archives is Install from the release archive.
What you learned
- The worker goes first, the studio second; the import and the first invitation run once, on the studio app, through
clever ssh, without--config. /readyzsays whether this instance serves writes, and how far the journal's shipping to the bucket is behind (rpoMs).clever logsnever stops by itself: stop it by its process id.
Where to go next
- Invite the team: Invitations.
- Set alerts: Monitoring. Schedule a restore drill.
- The next deploy: Redeploys.
- The server's commands:
studio-server/src/server/main.ts; the CLI reference: The server's CLI.