Apps · 应用托管

From your folder to their private link

Deploy a prototype that runs in Docker to a PitchStation host. Get an HTTPS address, a private link for each person, and redeploys that keep the address and the links.

Apps is switched on per person by your PitchStation admin. Not on yet? Ask them for “Deploy hosted apps (containers)”. How access works ↓

  • 5ways in: AI skill, client, MCP, REST, web page
  • 0rebuilds to change the address or who can open it
  • 2checks of your Compose file: at the dry run and on the host
  • 3DNS views that must agree before your own domain goes live
The route

Six stops from your laptop to their browser

This page follows one fictional prototype, demo-crm. Alex built it, and Jordan, an investor, needs to see it. Each stop says what Alex does and what PitchStation does along the way.

  1. 01BuiltIt runs in Docker on Alex’s laptop.
  2. 02AskedA dry run shows the plan. Nothing changes yet.
  3. 03DeployedOne operation builds, migrates, starts and routes it.
  4. 04ProvenReadiness checks that the address serves this app.
  5. 05SharedA private address, and a link just for Jordan.
  6. 06FixedA redeploy. Same address, same link.

Then: where it runs · heavy builds · looking after it · getting access

What you can rely on

Four promises, each with its limit

Each promise is printed next to its limit. The stops below show how they work.

Access is checked on the app’s host

A private app’s password, access links and end date are checked on its own host, from a policy file kept there. The check calls nothing outside the host, so it keeps working while PitchStation is unreachable.

How the gate works →
LIMITNew “Sign in with PitchStation” sign-ins need PitchStation to be reachable.

Every deploy is a release

Roll back to an earlier release with the skill, the client or the API. Its Compose file starts again, and your domains, access rule, budget and last applied environment stay as they are.

Releases and rollback →
LIMITA rollback restores code built on the host only when each release gives its images a new tag. It never undoes database migrations.

Your data can leave the host

Set up backups once. They run before each redeploy of a running app, daily if you ask, and whenever you choose. PitchStation keeps its own copies, which you can download.

Backups and moves →
LIMITBackups larger than 512 MB, the default limit, stay on the app’s host only.

Shared hosts enforce the rules

On a shared host each app runs inside its own memory, CPU and process budget. Compose settings that reach outside the app are refused before anything is built.

Shared-host rules →
LIMITOn a server registered to your own account, the same checks only warn unless the server is set to enforce them.
Stop 01 · Built

It runs on your machine. That is the starting line.

Apps takes a project folder. If the folder has a Compose file, the host runs that file. A Vite and React app built with npm, or a Next.js app set to output: 'standalone' with npm or pnpm, needs no Compose file: the packager writes a Dockerfile and a Compose file into the upload for you. Your folder is not changed.

The packager runs on your machine. It leaves out .git, node_modules, .env files, key files, build caches and local databases, and it keeps templates such as .env.example. It refuses a symlink or any file that contains a private key. Add your own rules in a .pitchstationignore file.

The app contract

  • The web service listens on 0.0.0.0 inside its container, on the container port: 3000 unless you choose another when you create the app.
  • Only the web service publishes a port, and only as 127.0.0.1:${HOST_PORT}:<container port>.
  • The health path answers HTTP 200 within about 60 seconds of starting, with no redirect and no login.
  • Data lives in named volumes. They survive every release; files written inside the container’s own file system do not.
  • The slug names the address, and it cannot be changed later.
What goes into the uploadYour folder on the left; the packager on your machine keeps compose.yaml, web, db/migrations and .env.example. It leaves out .env, node_modules, .git, .next and key files such as id_ed25519, and a local database folder with a warning. It refuses to send anything containing a symlink, a device or a private key. For a Vite or Next.js app with no Compose file it adds a generated Dockerfile.pitchstation and compose.yaml to the upload only. Limits: 80 MiB compressed, 256 MiB unpacked, 20,000 files. Your folder ~/projects/demo-crm compose.yaml web/ db/migrations/ .env.example template, kept .env left out node_modules/ left out .git/ left out .next/ left out id_ed25519 left out pgdata/ left out, with a warning Packager runs on your machine follows .pitchstationignorewrites a Dockerfile and aCompose file for a Vite orNext.js app that has none Refused: nothing is sent a symlink or a devicea file holding a private key The upload tar.gz, sent to PitchStation compose.yaml web/ db/migrations/ .env.example Vite or Next.js, no Compose file: + Dockerfile.pitchstation+ compose.yaml (generated) Limits: 80 MiB compressed,256 MiB unpacked, 20,000 files package upload What goes into the uploadYour folder on the left; the packager on your machine keeps compose.yaml, web, db/migrations and .env.example. It leaves out .env, node_modules, .git, .next and key files such as id_ed25519, and a local database folder with a warning. It refuses to send anything containing a symlink, a device or a private key. For a Vite or Next.js app with no Compose file it adds a generated Dockerfile.pitchstation and compose.yaml to the upload only. Limits: 80 MiB compressed, 256 MiB unpacked, 20,000 files. Your folder ~/projects/demo-crm Kept compose.yaml web/ db/migrations/ .env.example template, kept Left out .env node_modules/ .git/ .next/ id_ed25519 pgdata/ left out, with a warning package Packager runs on your machine follows .pitchstationignorewrites a Dockerfile and a Composefile for a Vite or Next.js appthat has none Refused: nothing is sent a symlink or a devicea file holding a private key upload The upload tar.gz, sent to PitchStation compose.yaml web/ db/migrations/ .env.example Vite or Next.js, no Compose file: + Dockerfile.pitchstation+ compose.yaml (generated) Limits: 80 MiB compressed,256 MiB unpacked, 20,000 files
The packager runs on your machine. It leaves out .env files, keys and clutter, and it never rewrites your project folder.

More: the app contract · packaging · User manual: what gets packaged

Stop 02 · Asked

One sentence, then a dry run

Alex asks an AI assistant that has the PitchStation Apps skill. The skill checks which hosts Alex may use, makes the project deployable and creates the app. Then it runs a dry run and shows the plan before anything is applied.

A deploy’s dry run packs the folder, checks the Compose file and returns the plan: the files, the address, the access rule and any warnings. Nothing on the host changes until you apply with a key. Rollbacks, environment changes, budgets, restores and moves also start with a dry run, and domain and access changes start with a plan you review.

Say to your assistantUse the create-pitchstation-app skill. Make ~/projects/demo-crm deployable, then deploy it to PitchStation as a private app. Show me the dry-run plan before applying.

The skill never asks for your token or password in chat. For a private app it writes the password to a file that you read in your own terminal.

Or run the client yourself

# once: create the app, private from the start
ps-apps create --file app.json --private \
  --password-file ~/.pitchstation/demo-crm.password

# dry run: the plan comes back, nothing changes
ps-apps deploy --app 41 --source ~/projects/demo-crm \
  --marker "Demo CRM · Pipeline overview"

# apply with a key you keep; a key never deploys twice
ps-apps deploy --app 41 --source ~/projects/demo-crm \
  --marker "Demo CRM · Pipeline overview" \
  --apply --key demo-crm-20261002-01 --watch

ps-apps stands for ~/.pitchstation/ps-apps, the launcher the skill’s Setup installs for the one-file Apps client. It is not on your PATH, so type the full path.

What one sentence sets offWhat the create-pitchstation-app skill does after “Deploy to PitchStation as a private app.”: it lists the hosts you may use, reuses this project’s app, asks once whether the app is public or private (recommending private), and makes the project deployable without committing. PitchStation creates the app with the password kept in a file and runs a dry run; anything unexpected comes back to you before it is applied. The deploy is applied as one operation with a key, readiness is checked, and your assistant reports the address, the access, the app ID and where the password file is. You Your assistant PitchStation You say it “Deploy to PitchStation as a private app.” Checks the hosts you may use ps-apps targets your hosts, shared hosts, your quota Reuses this project’s app never makes a second one Asked once, if you did not say public or private? It recommends private. Makes the project deployable lists the files it added and does not commit them Creates the app ps-apps create --private … the password stays in a file Runs a dry run ps-apps deploy --source … plan, file list, Compose check Anything unexpected comes back to you before anything is applied Applies it as one operation --apply --key demo-crm-…-01 operation ID at once; runs on the host Checks readiness ps-apps readiness DNS, TLS, access, identity, assets Reports back the address, the access, the app ID and where the password file is
What the skill does after one sentence. Amber marks the two points where it comes back to you.

Five ways in, one API

The skill is one way in. The Apps client, the MCP tools, the REST API and the Apps page reach the same API, and every call checks the same Apps permission.

AI skill

create-pitchstation-app

Best for
Asking Claude Code, Codex or another agent with a shell to make a project deployable and ship it.
Does
Everything in the comparison below. It drives the Apps client for you, and uses the REST API to stop or delete an app.
Not here
Accepting publisher terms. You accept them yourself on the Apps page.

Apps client

pitchstation-apps.cjs

Best for
Terminals and CI. One Node file (Node 20 or later) with no dependencies; each result is one JSON line. It reads the token from the environment and refuses tokens or passwords on the command line.
Does
Create, deploy, image archives, domains, access, access links, environment, rollback, backups, moves, budgets, deploy settings, status, logs and readiness.
Not here
Stopping or deleting an app (use the REST API). Accepting terms, which needs a signed-in browser session.

MCP tools

six pitchstation_app_* tools

Best for
Assistants that work through tools. The six are list, status, logs, deploy, operation and readiness.
Does
Deploys (with an image archive if you have one), follows, retries and cancels operations, reads status and logs, and runs readiness.
Not here
Creating apps. Also domains, access, environment, budgets and rollback: those are reviewed plans guarded by a version check, so they stay in the skill, the client and the REST API; the Apps page also does domains, access and budgets.

REST API

/api/apps

Best for
Your own tooling. It is the complete surface, described in OpenAPI at /api/openapi-apps.json.
Does
Every action, including stop and delete. Changes that run as operations take an Idempotency-Key: repeat a request with the same key and you get the same operation back. Send Prefer: respond-async to get 202 and an operation to follow at once.
Not here
Accepting publisher terms: that needs a signed-in browser session.

Apps page

/apps.html

Best for
Owners working by hand, signed in.
Does
Hosts and spend, terms, domains, access and end date, access links, backups and restore, moves, read-only services, deploy settings, image archives (list and remove), status, logs, budgets and operations.
Not here
Creating, deploying, environment changes, rollback, stop and delete. It lists image archives but does not upload them.
Compare all five, task by task
TaskAI skillApps clientMCP toolsREST APIApps page
Create an appyescreate—POST /api/apps—
Deploy and redeployyesdeploypitchstation_app_deployPOST …/deploy—
Build elsewhere (image archive)yesarchive, deploy --image-archiveimage_archive on deployPUT …/imageslist and remove
Follow, retry, cancelyesoperation, retry, cancelpitchstation_app_operation…/operations/{op}, …/operations/{op}/retry, …/operations/{op}/cancelyes
Settle an uncertain outcomeyesreconcile—…/operations/{op}/reconcileyes
Readiness and receiptyesreadiness, receiptpitchstation_app_readiness (readiness only)…/readiness, …/publication-receiptyes
Status and logsyesstatus, logspitchstation_app_status, pitchstation_app_logs…/status, …/logsyes
Domains, access, end dateyesdomains, policy—…/domain-config, …/publication-policyyes
Access linksyeslinks—…/access-linksyes
Environment variablesyesenv—PATCH …/env—
Rollbackyesrollback—POST …/rollback—
Budgetyesresources—PATCH …/resourcesyes
Backups and restoreyesbackup-config, backups, restore—…/backup-config, …/backups, …/restoreyes
Move to another hostyesmove, moves—POST …/moveyes
Isolated hosts and spendyeshost-catalog, hosts, spend—/api/apps/hosts, /api/apps/spendyes
Stop and deletethrough REST——POST …/stop, DELETE /api/apps/{id}—
Accept publisher termsyou accept on the Apps page——browser session onlyyes

… stands for /api/apps/{id}, and {op} for an operation ID.

The Apps page cannot create or deploy an app. It is where you change addresses and access, share links, back up, move, and watch status, logs and operations.

More: set up once · create the app · User manual: quick start · which way in

Stop 03 · Deployed

Apply once. One operation takes it from upload to live.

When Alex applies, PitchStation answers at once with an operation ID and does the work on the app host. It re-checks DNS for every hostname, checks the Compose file, sets the app’s budget and builds the images, or loads images built elsewhere. If backups are set up and the app already has a release, it backs up the data. Then it runs the migration, starts the containers and waits for the health check. Last, it routes the address, with a certificate for each hostname.

Once PitchStation has accepted the deploy, you can close the laptop: the operation keeps running. If the connection drops, send the identical command again with the same key. You get the same operation back, not a second deploy.

If anything fails before the new containers start, the previous release keeps serving. If the new release fails its health check, the operation fails, and the address serves the failing release until you deploy a fix or roll back. The failed step keeps its last lines of output, with stored secrets masked. When PitchStation cannot tell what happened on the host, it stops the app’s queue and asks someone to check, instead of guessing.

One deploy operation, from upload to liveYou apply with a key; PitchStation accepts one operation with an ID, and the same key returns the same operation. On the host it re-checks DNS for every hostname, then runs preflight, upload, upload-images, write-env, compose-policy, resources, build or load-images, backup, backup-pull, pre-deploy hooks, migrate, up, health, post-deploy hooks, activate, policy-runtime, a tls step per hostname and apply-routing; dashed steps run only when set up. A failure up to migrate leaves the previous release serving. A failure at up, health or activate stops the operation; after a failed health check the address serves the failing release until you deploy a fix or roll back. Routing and certificate steps keep only an error code; post-deploy hooks and backup-pull only warn. Then the app is live and readiness runs. Your machine package the folderdry run: nothing changesapply with a key apply Accepted 202 · operation ID same key → same operationkeeps going if you leave On the app host first: DNS re-checked for every hostname preflight upload upload-images write-env compose-policy resources build | load-images backup backup-pull pre-deploy-N migrate up health post-deploy-N activate policy-runtime tls:<hostname> apply-routing fails here: the previous release keeps serving. A failed migration or pre-deploy hook also waits for you to check your database. fails here: the operation stops. After a failed health check, the address serves the failing release until you deploy a fix or roll back. fails here: certificate or routing error; the step keeps only its error code only warns: the deploy goes on dashed: runs only when you set it up (image archive, backups, hooks, migration) Live: https://demo-crm.apps-ap.pitchstation.ai readiness runs at the end One operation at a time per app. The app’s own steps keep their last output lines for 30 days, stored secrets masked.An uncertain result stops the app’s queue until you or an admin checks. Follow with --watch, or close the laptop. One deploy operation, from upload to liveYou apply with a key; PitchStation accepts one operation with an ID, and the same key returns the same operation. On the host it re-checks DNS for every hostname, then runs preflight, upload, upload-images, write-env, compose-policy, resources, build or load-images, backup, backup-pull, pre-deploy hooks, migrate, up, health, post-deploy hooks, activate, policy-runtime, a tls step per hostname and apply-routing; dashed steps run only when set up. A failure up to migrate leaves the previous release serving. A failure at up, health or activate stops the operation; after a failed health check the address serves the failing release until you deploy a fix or roll back. Routing and certificate steps keep only an error code; post-deploy hooks and backup-pull only warn. Then the app is live and readiness runs. Your machine package the folderdry run: nothing changesapply with a key apply Accepted 202 · operation ID same key → same operationkeeps going if you leave On the app host first: DNS re-checked for every hostname preflight upload upload-images write-env compose-policy resources build | load-images backup backup-pull pre-deploy-N migrate up health post-deploy-N activate policy-runtime tls:<hostname> apply-routing fails here: the previous releasekeeps serving; a failed migration orpre-deploy hook also waits for youto check your database fails here: the operation stops.After a failed health check, theaddress serves the failing release. fails here: certificate or routingerror; only its error code is kept only warns: the deploy goes on dashed: runs only when set up Live demo-crm.apps-ap.pitchstation.ai readiness runs at the end One operation at a time per app.Own steps keep their last lines for30 days, stored secrets masked.Uncertain results stop the queue.
Each apply is one operation with these steps, in this order. Send the same key again and you get the same operation back, never a second deploy.

Same key, same operation

  • Apply --key demo-crm-…-01first try
    Operation Acreated
  • Same request again --key demo-crm-…-01after a dropped connection
    Operation Areturned again, marked as a duplicate
  • Changed request --key demo-crm-…-01same key, new source
    RefusedIDEMPOTENCY_KEY_REUSED
  • Your next deploy --key demo-crm-…-02a new key
    Operation Bcreated

Keys are 8 to 128 letters, digits, dots, underscores or hyphens.

Follow it, or walk away

queuedrunningsucceededfailedcancelled
  • waiting_external: a hostname’s DNS is not ready. It retries by itself for up to about 75 to 90 minutes.
  • cancel_requested: stops at the next safe point.
  • Retry safe steps runs a failed operation again and skips the steps that already succeeded.
  • One at a time: while an operation runs, another change for the same app gets OPERATION_BUSY.
  • --watch follows an operation for up to five minutes. The operation does not stop when the watch does.
  • Uncertain? If only your containers were involved, you inspect the host, check your database and confirm. Routing and certificate cases go to an admin.
Limits worth knowing
WhatLimit
Upload80 MiB compressed · 256 MiB unpacked · 20,000 files
Hostnamesup to 10 per app, the platform address included
Apps on shared hosts3 per person, unless an admin changes it
Budget per app512 MB memory, 1 CPU and 256 processes by default
Access linksup to 50 active per app; each can expire up to a year ahead
Sessions12 hours, never past the app’s end date
Plans and proofa domain or access plan lasts 15 minutes; a readiness result, 5
Requests to your appbodies up to 64 MiB · 300-second read timeout · WebSockets pass through
Logsup to 1,000 lines or 256 KiB a read · 10 status or log reads a minute for each app
Failed-step outputthe last lines, kept 30 days
Backups1 to 10 kept on the host (5 by default) · PitchStation keeps the newest 10, each up to 512 MB
Image archivesnewest 3 kept, plus the running release’s · up to 1,024 MB each*

* The network edge in front of PitchStation may refuse a large archive below this size. The client then says so.

More: deploy a release · operate · User manual: what a deploy does · all limits

Stop 04 · Proven

Proven, not just HTTP 200

A page that loads proves little. It could be an old server, a default page or another app. Readiness tests every address of the app: DNS points at the right host, the certificate is valid, the access rule behaves as set, the home page carries the app’s identity text and headers, and its scripts and stylesheets load.

Every deploy runs readiness at the end, and so do rollbacks and domain or access changes. You can run it again from the Apps page or the client. A result holds for five minutes. It also says what it did not check: video playback, language switching and 3D still need a person with a browser.

What readiness provesReadiness tests each address, here demo-crm.apps-ap.pitchstation.ai, five ways: DNS points at the app host and three resolvers agree (own domains also need their TXT proof); the TLS certificate is valid for the name; private apps answer anonymous visitors with 401, public apps with no 401, 403 or login form; the home page shows Demo CRM · Pipeline overview and its headers name this app and release; scripts, stylesheets and listed files answer 200 and are not HTML. Verified ready holds five minutes. Video, language switching and 3D are not certified. Readiness check after every deploy, or when you ask https://demo-crm.apps-ap.pitchstation.ai every address gets the same checks DNS points at the app host,the same from threeresolvers; own domainsalso need the TXT proof TLS the certificate is validfor this name Access private: anonymousvisitors get 401public: no 401 or 403,and no login form Identity the home page shows“Demo CRM · Pipelineoverview”; headers namethis app and release Assets scripts, stylesheets andlisted files answer 200and are not HTML Verified ready (HTTP/TLS/policy/assets) holds 5 minutes; any configuration, release or status change makes it stale Not certified: video playback, languageswitching, 3D. Check them in a browser. What readiness provesReadiness tests each address, here demo-crm.apps-ap.pitchstation.ai, five ways: DNS points at the app host and three resolvers agree (own domains also need their TXT proof); the TLS certificate is valid for the name; private apps answer anonymous visitors with 401, public apps with no 401, 403 or login form; the home page shows Demo CRM · Pipeline overview and its headers name this app and release; scripts, stylesheets and listed files answer 200 and are not HTML. Verified ready holds five minutes. Video, language switching and 3D are not certified. Readiness check after every deploy, or when you ask every address gets the same checks demo-crm.apps-ap.pitchstation.ai DNS points at the app host, the samefrom three resolvers; your owndomains also need the TXT proof TLS the certificate is validfor this name Access private: anonymous visitors get 401public: no 401 or 403, and nologin form Identity the home page shows “Demo CRM ·Pipeline overview”; headers namethis app and release Assets scripts, stylesheets and listedfiles answer 200 and are not HTML Verified ready (HTTP/TLS/policy/assets)holds for 5 minutes Not certified: video playback,language switching, 3D.
Readiness is evidence that this address serves this app, with these access rules. Each deploy runs it at the end.

Public app? Declare that the app has no login or expiry of its own. Until you do, readiness will not certify it. Why

Hand over proof, not passwords

Copy redacted receipt gives the addresses, the access summary, the release and the latest readiness result. Passwords are never in it.

Identity text

Vite apps get an identity marker automatically. For Next.js and Compose apps, pass --marker with 12 or more characters the home page always shows, or set Expected page identity on the Apps page.

More: before you announce it · User manual: readiness

Stop 05 · Shared

Shared privately, one person at a time

A private app asks for a password before a request reaches your containers. The check runs on the app’s own host, so the app stays private even while PitchStation itself is unreachable.

For a named person, create an access link. It lets that one person in without the password. It can expire, and you can revoke it on its own. Alex makes one for Jordan and copies it from the Apps page.

Colleagues with a PitchStation account can sign in with it instead. List the people, or a team, and the app’s sign-in page offers Sign in with PitchStation.

The Access links panel of the Apps page, with fictional data. A form asks For whom, with the example Alice (investor), and an optional expiry, with a Create link button. The Links table lists Priya (design review), active, never expires, opened once; Jordan (investor), active, with an expiry date, opened 3 times; and a third link, revoked, opened 5 times. Active links have Copy link and Revoke buttons.
The Access links panel on the Apps page, with fictional data: one link per person, when it expires, and how often it was opened.
  • Passwords are 12 to 72 bytes, chosen and kept by you. A new password signs everyone out.
  • Sessions last 12 hours and never outlive the end date you set.
  • Up to 50 active links per app. Each can expire, up to a year ahead.
  • The Opened count appears where the app’s host runs the current host reporter, which an admin installs when onboarding the host.
  • After sign-in, your app gets the visitor’s own Authorization header. The gate’s credentials never reach it.
  • Webhooks and OAuth callbacks can skip the password on up to five callback paths. The end date still applies, and your app must verify each callback itself.
  • Set an end date, and after it every address answers 410.
How a private app is enforced on its hostRequests to a private app reach nginx on its host, which asks a policy verifier on the same host whether each may pass. The verifier reads only a local policy file that PitchStation writes when something changes, never calls PitchStation, and denies without a valid policy. Allowed requests reach the containers on a loopback port with the visitor’s own Authorization header. Other answers come from the verifier (the sign-in page then a 12-hour session, HTTP Basic with user preview for API clients) or from nginx itself (410 after the end date, 404 for a disabled name or takedown). Passwords, links, end dates, 404s and certificate renewal hold while PitchStation is unreachable; new account sign-ins, changes, deploys, status and logs need it. Browser, first visit no session yet Browser with a link /__ps/enter?t=… API client curl, scripts PitchStation writes the policy filewhen something changes App host nginx TLS for eachhostname asks the verifierbefore every request Policy verifier on this host, loopback onlyreads this host’s policy fileno calls to PitchStationno policy, or a broken one: deny demo-crm containers 127.0.0.1:<host port> gets the visitor’s ownAuthorization header What a visitor gets allowed: your app no session yet: thesign-in page, then a12-hour session API client: HTTP Basic,user preview after the end date: 410 disabled name ortakedown: 404 Holds while PitchStation is unreachable passwords, access links, end dates, 404s, certificate renewal Needs PitchStation new Sign in with PitchStation sign-ins, every changeand deploy, status and logs may this request pass? allowed every other answer, from nginx or the verifier How a private app is enforced on its hostRequests to a private app reach nginx on its host, which asks a policy verifier on the same host whether each may pass. The verifier reads only a local policy file that PitchStation writes when something changes, never calls PitchStation, and denies without a valid policy. Allowed requests reach the containers on a loopback port with the visitor’s own Authorization header. Other answers come from the verifier (the sign-in page then a 12-hour session, HTTP Basic with user preview for API clients) or from nginx itself (410 after the end date, 404 for a disabled name or takedown). Passwords, links, end dates, 404s and certificate renewal hold while PitchStation is unreachable; new account sign-ins, changes, deploys, status and logs need it. Browser, first visit no session yet Browser with a link /__ps/enter?t=… API client curl, scripts App host nginx TLS for each hostname asks the verifier beforeevery request may this request pass? Policy verifier on this host, loopback onlyreads this host’s policy fileno calls to PitchStationno policy or a broken one: deny allowed demo-crm containers 127.0.0.1:<host port> gets the visitor’s ownAuthorization header Other answers come from nginx or theverifier: see “What a visitor gets”. PitchStation writes the policy file when something changes What a visitor gets allowed: your app no session yet: the sign-in page,then a 12-hour session API client: HTTP Basic withthe user preview after the end date: 410 disabled name or takedown: 404 Holds if PitchStation is unreachable passwords, access links, end dates,404s and certificate renewal Needs PitchStation new account sign-ins, changes,deploys, status and logs
The gate lives on the app’s own host. If PitchStation is down, your private app stays private, and its end date still holds.

If PitchStation is unreachable

Keeps working on the app’s host

  • Visitors reach your app.
  • Password and access-link sign-ins, and sessions already open.
  • The end date (410) and redirected or disabled addresses.
  • Takedowns (404).
  • Certificate renewal.

Waits until PitchStation is back

  • New Sign in with PitchStation sign-ins.
  • Deploys, rollbacks and every change, including new and revoked links.
  • Status, logs and readiness checks.
Three ways a person gets into a private appPassword, for a small group: 12 to 72 bytes, typed on the sign-in page, in for 12 hours; a new password signs everyone out. Access link, for one named person such as Jordan (investor): optional end date within a year, in without the password for 12 hours, revoked on its own with its sessions; up to 50 active links, with open counts where the host reports them. Sign in with PitchStation, for listed people and teams: checked at sign-in against the owner, listed people and teams, Not on the list for anyone else, then a 5-minute token for a 12-hour session; removal takes effect when the session ends. All three stop at the end date (410). Password for a small group You choose it: 12 to 72 bytes, and hand it over separately The visitor types it on the sign-in page In for 12 hours A new password signs everyone out. Access link for one named person You create a link for Jordan (investor) optional end date, within a year Jordan opens it: https://…/__ps/enter?t=… In, no password, for 12 hours Revoke it alone; its sessions end too.Up to 50 active links per app.Opened: 3 times · last …,where the host reports it. Sign in with PitchStation for listed people and teams The app’s sign-in page offers Sign in with PitchStation (signs in to PitchStation first) PitchStation checks, right now: the owner, a listed person, or a member of a listed team In for 12 hours 5-minute token Not on the list Removing someone takes effect whentheir session ends. Turning it offends every account session. All three stop at the end date you set: after it, every address answers 410. Three ways a person gets into a private appPassword, for a small group: 12 to 72 bytes, typed on the sign-in page, in for 12 hours; a new password signs everyone out. Access link, for one named person such as Jordan (investor): optional end date within a year, in without the password for 12 hours, revoked on its own with its sessions; up to 50 active links, with open counts where the host reports them. Sign in with PitchStation, for listed people and teams: checked at sign-in against the owner, listed people and teams, Not on the list for anyone else, then a 5-minute token for a 12-hour session; removal takes effect when the session ends. All three stop at the end date (410). Password for a small group You choose it: 12 to 72 bytes, and hand it over separately The visitor types it on the sign-in page In for 12 hours A new password signs everyone out. Access link for one named person You create a link for Jordan (investor) optional end date, within a year Jordan opens it: https://…/__ps/enter?t=… In, no password, for 12 hours Revoke it alone; its sessions end too.Up to 50 active links per app.Opened: 3 times · last …, wherethe host reports it. Sign in with PitchStation for listed people and teams The app’s sign-in page offers Sign in with PitchStation (signs in to PitchStation first) PitchStation checks, right now: the owner, a listed person, or a member of a listed team Anyone else: “Not on the list” 5-minute token In for 12 hours Removing someone takes effect whentheir session ends. Turning it offends every account session. All three stop at the end date:after it, every address answers 410.
Use the password for a small group, a link for each named person, and PitchStation sign-in for colleagues and teams.

Account sign-in, callback paths and cache paths use a newer access check. PitchStation installs it on the app’s host with the app’s next deploy or access change.

More: addresses and access · access links · callbacks, caching and sign-in · User manual: who can open your app

Stop 06 · Fixed

Same afternoon: the fix is live on the same link

Jordan opens the link and finds a bug on the deals page. Alex fixes it and deploys again with a new key. The domains, the password and the link Jordan already has all stay as they were, so Jordan reloads the page and sees the new release.

When a deploy fails, the operation shows the failed step’s last lines with stored secrets masked. In the example below, the new release failed its health check because a setting the new code needs is missing. Its container exits during startup, so nothing answers on the app’s port, and visitors get an error page (502) until the fix is deployed or the app is rolled back. The fix is to add the setting to the app’s environment and deploy again with a new key. If a step failed for a passing reason, Retry safe steps runs the operation again and skips the steps that already succeeded.

Every deploy is a release you can return to. Roll back with the skill, the client or the API: PitchStation starts that release’s Compose file again and keeps the domains, the access rule, the budget and the last environment you applied. A rollback does not build. An image built on the host keeps the same name from release to release, so a rollback runs its newest build, unless each release gives it a new tag, such as image: demo-crm-web:r34. A rollback never undoes database migrations, so write migrations that are safe to run forward.

The Operations panel of the Apps page for a failed deploy, with fictional data. Steps build, backup, backup-pull, migrate and up succeeded; step health failed with STEP_FAILED. Its output is open: the app started and connected to a database whose address is shown as [redacted:DATABASE_URL], then stopped with the error “SESSION_SECRET is not set. Add it to the app environment and deploy again.” A Retry safe steps button is below.
A failed deploy on the Apps page, with fictional data: the health check failed, and the step’s last lines show why. The database address is masked.

After a failed health check, the failing release is what the address serves. Its containers replaced the old ones before the check ran, and they stay until you deploy a fix or roll back. If they do not start, as above, visitors get an error page. Deploying the fix with a new key is the surest way back. To roll back instead, name the release: the app still records the last good release as current, and ps-apps list shows its ID as currentRelease. A client updated by re-running the skill’s Setup also has ps-apps releases --app 41, which lists every kept release. A rollback without a release ID skips that release and goes one further back. Run ps-apps rollback --app 41 --release ID, then apply with a new key; it brings that release’s code back only if its images have their own tag.

Releases, rollback and the data that staysReleases 31 to 34 kept on the host. Release 33 is the last good release and still the current release; release 34 failed its health check and is at the address now (if its containers do not start, visitors get an error page). Route A, rollback --release 33, returns to release 33; route B, a rollback without an ID, skips 33 and goes to 32. A rollback starts that release’s Compose file again without building, so images built on the host under one name run their newest build; a new tag in every release, such as image: demo-crm-web:r33, brings the old code back. The volume ps-demo-crm_data is kept across releases. A rollback keeps domains, access, budget and the last environment, and never undoes migrations. With backups set up, each deploy of a running app backs up first. RELEASES KEPT ON THE HOST release 31 healthy kept release 32 healthy kept release 33 last good release the current release release 34 failed its health check at the address now deploy deploy deploy A B A Route A · ps-apps rollback --app 41 --release 33: back to the last good release. B Route B · no release ID: the rollback skips release 33 and goes to release 32. Images builton the host same name in every release: a rollback restores the Compose file, but runs the newest build a new tag in every release, such as image: demo-crm-web:r33: a rollback brings that build back ps-demo-crm_data named volume: kept across every release; files written inside a container are not A rollback keeps the domains, the access rule, the budgetand the last environment you applied A rollback does not undo database migrations a backup before each deploy of arunning app, when backups are set up Releases, rollback and the data that staysReleases 31 to 34 kept on the host. Release 33 is the last good release and still the current release; release 34 failed its health check and is at the address now (if its containers do not start, visitors get an error page). Route A, rollback --release 33, returns to release 33; route B, a rollback without an ID, skips 33 and goes to 32. A rollback starts that release’s Compose file again without building, so images built on the host under one name run their newest build; a new tag in every release, such as image: demo-crm-web:r33, brings the old code back. The volume ps-demo-crm_data is kept across releases. A rollback keeps domains, access, budget and the last environment, and never undoes migrations. With backups set up, each deploy of a running app backs up first. RELEASES KEPT ON THE HOST release 34 failed health check at the address now release 33 last good release the current release release 32 healthy kept release 31 healthy kept A B A Route A: name release 33 to goback to the last good release. B Route B: no release ID skips 33and goes to release 32. Images built on the host same name in every release: arollback runs the newest build a new tag in every release: arollback brings that build back ps-demo-crm_data named volume, kept acrossevery release A rollback keeps the domains, the access rule, thebudget and the last environmentyou applied. A rollback does not undo database migrations. Before each deploy of a running app,a backup, when backups are set up.
After a failed health check the failing release stays at the address. Name the release you return to, and tag built images in every release so a rollback brings their code back.

Changed a NEXT_PUBLIC_ or VITE_ value? Those are baked in when the app is built. The Apps page tells you the running release still has the old value until you deploy again.

More: troubleshooting · environment variables · build-time values · User manual: roll back · after a failed health check

Under the hood · Hosts

Where it runs, and what a shared host refuses

Apps run on shared hosts that PitchStation runs for teammates, or on a host of your own. On shared hosts each person can have three apps, unless an admin changes the limit. Leave the host out when you create an app and PitchStation places it on a host you may use. It prefers the region you ask for, if you name one, then the host with the most free budget memory. It says why it chose that host, and lists every host it passed over with the reason.

Want a machine nobody else uses? Reserve an isolated host on the Apps page or with the client, and an administrator launches it. It counts against the monthly spend cap on your account, which dev instances share. A reservation nobody launches within 24 hours lapses.

A shared host holds other people’s apps, so its rules refuse instead of warn. Each app gets its own budget: 512 MB of memory, one CPU and 256 processes by default, with no swap. The Compose file is checked at your dry run and again on the host before anything is built.

Check the architecture before you build. An ARM64 host needs ARM64 images. ps-apps targets lists each host you may use, with its architecture, region and free slots.

How an app is placedYou name a host, or PitchStation places the app. Hosts are passed over if not approved, paused, full, the wrong CPU type, without budget room, over your quota or low on memory, each listed with its reason. The rest are ordered by the region you ask for, if any, then the most free budget memory and the fewest apps, and the choice comes with its reason. Hosts you may use: shared hosts (teammates’ apps too; rules refuse), isolated hosts (yours alone; strict allowlist) and your own server (rules warn unless set to enforce). You create an app name a host, or letPitchStation place it Passed over if… not approved paused no free slot wrong CPU type no budget room over your quota low free memory each host passed over is listed,with its reason Then ordered by 1 the region you ask for 2 most free budget memory 3 fewest apps Chosen host with the reasonit was chosen Hosts you may use: Shared host teammates’ apps too · rules refuse Isolated host yours alone · strict allowlist Your own server rules warn unless set to enforce How an app is placedYou name a host, or PitchStation places the app. Hosts are passed over if not approved, paused, full, the wrong CPU type, without budget room, over your quota or low on memory, each listed with its reason. The rest are ordered by the region you ask for, if any, then the most free budget memory and the fewest apps, and the choice comes with its reason. Hosts you may use: shared hosts (teammates’ apps too; rules refuse), isolated hosts (yours alone; strict allowlist) and your own server (rules warn unless set to enforce). You create an app name a host, or let PitchStationplace it Passed over if… not approved paused no free slot wrong CPU type no budget room over your quota low free memory each host passed over is listedwith its reason Then ordered by 1 the region you ask for 2 most free budget memory 3 fewest apps Chosen host with the reason it was chosen Hosts you may use: Shared host teammates’ apps too · rules refuse Isolated host yours alone · strict allowlist Your own server rules warn unless set to enforce
Leave the host out and PitchStation places the app, and says why. ps-apps targets lists each host you may use, with its architecture, region and free slots.
Shared host or isolated host
ComparedShared hostIsolated host
Who else runs apps on itTeammatesNobody else
How you get itAvailable once Apps is switched on for youYou reserve it on the Apps page or with the client; an administrator launches it
Compose rulesRisky settings refusedStrict allowlist: anything not on the list is refused
BudgetsEnforced, no memory overcommitWarn only, unless the server is set to enforce them
Outbound trafficOpen, unless an admin restricts the hostRestricted: no outbound mail, no cloud metadata service, new connections rate-limited
Counts againstYour shared-host limit: 3 apps unless an admin changes itYour monthly spend cap, shared with dev instances
Holds—3, 6, 12 or 20 apps, by size
Sizes and places—S, M, L or XL · arm64 or amd64 · Oregon or Singapore
Address<slug>.<base domain>, for example demo-crm.apps-ap.pitchstation.aithe host’s own label, for example demo-crm.h7.apps-ap.pitchstation.ai

A server registered to your own account can be a target too. There the same checks warn instead of refuse, unless the server is set to enforce them.

Guardrails on a shared hostA shared host checks each Compose file at your dry run and again before building. It refuses privileged containers, host networking, added capabilities, devices, the Docker socket, bind mounts outside the project, external volumes or networks, and ports on every interface; only the web service may publish, on 127.0.0.1. Refused means nothing is built. Each app runs in its own slice, by default 512 MB, one CPU, 256 processes and no swap, and is stopped inside it when over memory. Where the build ceiling is installed, builds get 40% of memory (at least 1 GB) and one CPU, one at a time. The host keeps 512 MB and does not overcommit. Each person has three apps on shared hosts unless an admin changes it. Shared host other people’s apps run here too Compose check ① at your dry run ② on the host, before building Refused privileged: true network_mode: host cap_add · devices /var/run/docker.sock bind mounts outside the project external volumes or networks ports: "8000:8000" Allowed ports: "127.0.0.1:${HOST_PORT}:3000" web service only Refused: nothing is built passes Each app runs in its own budget slice ps-app-41.slice demo-crm 512 MB · 1 CPU256 processes · no swap ps-app-….slice a teammate’s app its own budget ps-app-….slice a teammate’s app its own budget An app that goes over its memory is stopped inside its own slice. pitchstation-build.slice builds: by default 40% of memory (at least 1 GB),1 CPU, one build at a time on hosts set up with the build ceiling 512 MB keptfor the host itself no overcommit onshared hosts Each person: 3 apps on shared hosts, unless an admin changes it. Guardrails on a shared hostA shared host checks each Compose file at your dry run and again before building. It refuses privileged containers, host networking, added capabilities, devices, the Docker socket, bind mounts outside the project, external volumes or networks, and ports on every interface; only the web service may publish, on 127.0.0.1. Refused means nothing is built. Each app runs in its own slice, by default 512 MB, one CPU, 256 processes and no swap, and is stopped inside it when over memory. Where the build ceiling is installed, builds get 40% of memory (at least 1 GB) and one CPU, one at a time. The host keeps 512 MB and does not overcommit. Each person has three apps on shared hosts unless an admin changes it. Shared host other people’s apps run here too Compose check ① at your dry run ② on the host, before building Refused privileged: true network_mode: host cap_add · devices /var/run/docker.sock bind mounts outside the project external volumes or networks ports: "8000:8000" Allowed ports: "127.0.0.1:${HOST_PORT}:3000" web service only Refused: nothing is built passes Each app runs in its own budget slice ps-app-41.slice demo-crm 512 MB · 1 CPU · 256 processesno swap ps-app-….slice a teammate’s app, its own budget An app that goes over its memoryis stopped inside its own slice. pitchstation-build.slice builds: by default 40% of memory(at least 1 GB), 1 CPU, onebuild at a time where the build ceiling is installed 512 MB kept for the host itself no memory overcommit onshared hosts Each person: 3 apps on shared hosts,unless an admin changes it.
Other people’s apps share the machine, so the host refuses risky Compose settings and keeps every app inside its own budget.

More: strict hosts, egress and acceptable use · your own host and spend · User manual: hosts and your quota

Detour · Heavy builds

Too heavy to build on the host? Build it elsewhere.

On hosts set up with the build ceiling, a build gets a capped share of the machine: by default 40% of its memory (at least 1 GB) and one CPU, one build at a time. A build that needs more stops with BUILD_LIMIT_EXCEEDED, and the running release keeps serving.

The way around it is to build on your own machine, in CI or on a PitchStation Devbox, and send the images. The host loads them and builds nothing.

  1. Make the archive

    From the project folder, ps-apps archive --source . --platform linux/arm64 --output ../demo-crm-r34.tar.gz builds with your own Docker and saves the images outside the project, so they are not packed into the upload. Use a new file name for each build: the client never overwrites a file. Every service with build: needs an image: name:tag.

  2. Deploy with it

    ps-apps deploy --app 41 --source . --image-archive ../demo-crm-r34.tar.gz uploads the archive once and shows the plan; add --apply --key … to deploy. If PitchStation already holds a file with the same SHA-256, it is not sent again.

  3. The host loads it

    The dry run checks each image’s CPU architecture against the host’s. PitchStation keeps your newest three archives, plus the one the running release came from.

On a Devbox, devbox.py app-deploy runs both steps for you. Match the host’s CPU: linux/arm64 for an ARM64 host, linux/amd64 for x86.

Build elsewhere with an image archiveOn your machine, in CI or on a Devbox, ps-apps archive runs docker compose config and build for linux/arm64, then docker save into a new archive outside the project, here ../demo-crm-r34.tar.gz, with its SHA-256. deploy --image-archive uploads it once; a known SHA-256 is not sent again. PitchStation keeps your newest three archives plus the running release’s. The dry run refuses an image for the other CPU (IMAGE_ARCH_MISMATCH) and a built service without an image tag (IMAGE_ARCHIVE_INCOMPLETE). The host runs load-images, builds nothing and skips the build ceiling. Use linux/arm64 for ARM64 and linux/amd64 for x86. Your machine CI Devbox devbox.py app-deploy archive ps-apps archive--platform linux/arm64 docker compose config docker compose build docker save | gzip ../demo-crm-r34.tar.gz and its SHA-256 deploy --image-archive PitchStation uploaded once: skipped if thesame SHA-256 is already there keeps your newest 3, plus theone the running release uses the dry run checks: every built service has an image: name:tag each image matchesthe host’s CPU Refused at the dry run an image built for the other CPU IMAGE_ARCH_MISMATCH a built service with no image: tag IMAGE_ARCHIVE_INCOMPLETE App host load-images builds nothing, so thebuild ceiling is skipped up health … then the usual steps Match the host: linux/arm64 for ARM64,linux/amd64 for x86 Build elsewhere with an image archiveOn your machine, in CI or on a Devbox, ps-apps archive runs docker compose config and build for linux/arm64, then docker save into a new archive outside the project, here ../demo-crm-r34.tar.gz, with its SHA-256. deploy --image-archive uploads it once; a known SHA-256 is not sent again. PitchStation keeps your newest three archives plus the running release’s. The dry run refuses an image for the other CPU (IMAGE_ARCH_MISMATCH) and a built service without an image tag (IMAGE_ARCHIVE_INCOMPLETE). The host runs load-images, builds nothing and skips the build ceiling. Use linux/arm64 for ARM64 and linux/amd64 for x86. Your machine · CI · Devbox archive ps-apps archive--platform linux/arm64 docker compose config docker compose build docker save | gzip ../demo-crm-r34.tar.gz and its SHA-256 deploy --image-archive PitchStation uploaded once: skipped if the sameSHA-256 is already there keeps your newest 3, plus the onethe running release uses the dry run checks: every built service has an image: name:tag each image matches the host’s CPU Refused at the dry run an image built for the other CPU IMAGE_ARCH_MISMATCH a built service with no image tag IMAGE_ARCHIVE_INCOMPLETE App host load-images builds nothing, so the buildceiling is skipped up health then the usual steps Match the host: linux/arm64 forARM64, linux/amd64 for x86
When a build is too heavy for the host, build it where you have room and send the result.

More: prebuilt images · deploy settings · User manual: image archives · the build ceiling

After day one

Look after it from the Apps page

The Apps page in your PitchStation workspace is where an app lives after its first day. It lists only your own apps.

Status and logs

Each container’s state, health, restarts and memory against its budget. Up to 1,000 log lines a read, with stored secrets masked. Every log read is recorded.

Budget

Review a new memory, CPU or process limit, then apply it. On a shared host it applies without a restart.

Backups

Back up with a dump command or by copying named volumes, on demand or daily. Once backups are set up, each deploy of an app that already has a release backs up first. To restore, you review what is replaced and type the app’s slug.

Your own domain

Prove you own it with a TXT record, and PitchStation issues its certificate. The app is not rebuilt or restarted.

End date

Give a demo an end date. After it, every address answers 410, checked on the host for each request.

Move

Move the app to another host. Its data travels in a final backup, and the old copy stays stopped for 7 days by default.

Operations

Retry safe steps, cancel at a safe point, or settle an uncertain migration yourself after checking your database.

Read-only file system

Run chosen services with a read-only root file system and a writable /tmp, from the next deploy, rollback or environment change.

Your own domain

Bringing your own domain takes four steps, and the app keeps serving throughout.

Bringing your own domainPlan crm.example.com: PitchStation lists a TXT record at _pitchstation.crm.example.com with this app’s ownership value and an A record to the app host, both TTL 300; the plan holds 15 minutes. Prove: add both records (a CNAME to the host’s address also works). Verify: 1.1.1.1, 8.8.8.8 and the domain’s own name server must agree and see the TXT proof; nothing is issued yet. Apply: a Let’s Encrypt certificate is issued and the route switched, with no rebuild or restart. Keep the TXT record: every later routed change checks it. Before DNS is ready the operation waits and retries. Up to 10 hostnames per app, the platform address included. 1 Plan 2 Prove 3 Verify 4 Apply You plan crm.example.com the plan holds for 15 minutes TXT · TTL 300 _pitchstation.crm.example.com ps-app-41-… A · TTL 300 crm.example.com → the app host’s address You add both recordsat your DNS provider. A CNAME that ends at thehost’s address also works. 1.1.1.1 8.8.8.8 your DNS all three must agree andsee the TXT proof nothing issued or changed yet certificate issued for crm.example.com (Let’s Encrypt) route switched no rebuild, no restart Keep the TXT record every later routed change, deploys included, checks it again Applied before DNS is ready? The operation waits and retries. Up to 10 hostnames per app, the platform address included. Bringing your own domainPlan crm.example.com: PitchStation lists a TXT record at _pitchstation.crm.example.com with this app’s ownership value and an A record to the app host, both TTL 300; the plan holds 15 minutes. Prove: add both records (a CNAME to the host’s address also works). Verify: 1.1.1.1, 8.8.8.8 and the domain’s own name server must agree and see the TXT proof; nothing is issued yet. Apply: a Let’s Encrypt certificate is issued and the route switched, with no rebuild or restart. Keep the TXT record: every later routed change checks it. Before DNS is ready the operation waits and retries. Up to 10 hostnames per app, the platform address included. 1 Plan You plan crm.example.com the plan holds for 15 minutes TXT · TTL 300 _pitchstation.crm.example.com ps-app-41-… A · TTL 300 crm.example.com → the app host’s address 2 Prove You add both recordsat your DNS provider. A CNAME that ends at the host’saddress also works. 3 Verify 1.1.1.1 8.8.8.8 your DNS all three must agree and see theTXT proof; nothing issued yet 4 Apply certificate issued for crm.example.com (Let’s Encrypt), route switched no rebuild, no restart Keep the TXT record every later routed change, deploysincluded, checks it again Applied before DNS is ready? Theoperation waits and retries. Up to 10 hostnames per app, theplatform address included.
A working URL is not proof of ownership; the TXT record is. The app keeps serving while its address changes.

Backups and restore

Backups run on the app’s host. PitchStation also keeps copies of the smaller ones, and a restore checks the file before it uses it.

When backups run, where they are kept, how a restore runsBackups run before each redeploy of a running app, daily if turned on, on demand and before a move. Each runs on the app’s host, as a dump command or a copy of named volumes; the host keeps the newest 1 to 10 (5 by default). PitchStation copies backups of 512 MB or less, best effort, keeps 10 per app and records every download. A restore: a dry run shows what is replaced, you type the app’s slug, PitchStation sends its copy back if the host lost the file, the SHA-256 must match, then the data is restored and a health check runs, with code unchanged. Volume restores stop the app; a failed restore needs an admin. BACKING UP Before each redeploy Daily, if turned on Back up now Before a move Backup runs on the host a dump command in one ofyour services, or a copyof named volumes Kept on the host newest 1 to 10(5 by default)owner-only files Copy on PitchStation newest 10 per appdownload from the Apps page;every download is recorded copied to PitchStation if 512 MB or less (the default); best effort; larger backups stay on the host only RESTORING 1 · Dry run shows what will bereplaced 2 · Confirm type the app’s slug 3 · Copy back if the host lost it,PitchStation sends it 4 · Check the file’s SHA-256must match 5 · Restore then a health check;your code is unchanged copy back Volume restores stop the app while its volumes are replaced. A failed restore needs an admin to check. When backups run, where they are kept, how a restore runsBackups run before each redeploy of a running app, daily if turned on, on demand and before a move. Each runs on the app’s host, as a dump command or a copy of named volumes; the host keeps the newest 1 to 10 (5 by default). PitchStation copies backups of 512 MB or less, best effort, keeps 10 per app and records every download. A restore: a dry run shows what is replaced, you type the app’s slug, PitchStation sends its copy back if the host lost the file, the SHA-256 must match, then the data is restored and a health check runs, with code unchanged. Volume restores stop the app; a failed restore needs an admin. BACKING UP Before eachredeploy Daily, ifturned on Back up now Before a move Backup runs on the host a dump command, or a copy ofnamed volumes Kept on the host newest 1 to 10, 5 by default larger backupsstay on the host if 512 MB or less (the default),best effort Copy on PitchStation newest 10 per app; download itfrom the Apps page (recorded) RESTORING 1 Dry run: shows what will bereplaced. 2 Confirm: type the app’s slug. 3 Missing on the host? PitchStationsends its copy back first. 4 Check: the file’s SHA-256 mustmatch. 5 Restore, then a health check;your code is unchanged. Volume restores stop the app whileits volumes are replaced. A failedrestore needs an admin to check.
Backups are taken and kept on the app’s host; PitchStation keeps copies of those up to 512 MB. A restore is reviewed, confirmed with the app’s slug, and checked before it is used.

Move to another host

A move uses the app’s backup settings. Review it first: the plan shows the destination and why it was chosen, whether the address changes, how the data travels, the downtime and every step. The app is down from the moment the source stops until the destination serves. If the move fails before the switch, the destination is cleaned up and the source starts again. The stopped source stays for 7 days by default. When the move changed the address, the old address redirects (308) to the new one.

How a move to another host runsA move in seven phases: review (a dry run shows where, why, the address and the downtime), back up (final-backup, pull-release), stop the source (stop-source), set up the destination by building or loading the images and restoring the data (push-release, build, restore-data), start (migrate, up, health, activate), switch routing, and keep the stopped source 7 days (retain-source), with 308 redirects when the address changed (redirect-source). The app is down from the source stop until the destination serves; a failure before the switch cleans up the destination and restarts the source. source host destination host routing 1 · Review a dry run showswhere, why, theaddress, downtime 2 · Back up a final backupof your data final-backuppull-release 3 · Stop the source appstops stop-source 4 · Set up build or loadthe images,restore the data push-releasebuildrestore-data 5 · Start migrate, start,health check migrateup · healthactivate 6 · Switch routing pointsat the new host switchrouting 7 · Keep the old copy stays7 days; a changedaddress redirects redirect-sourceretain-source Down from the source stop until the destination serves Fails before the switch? The destination is cleaned up and the source starts again. How a move to another host runsA move in seven phases: review (a dry run shows where, why, the address and the downtime), back up (final-backup, pull-release), stop the source (stop-source), set up the destination by building or loading the images and restoring the data (push-release, build, restore-data), start (migrate, up, health, activate), switch routing, and keep the stopped source 7 days (retain-source), with 308 redirects when the address changed (redirect-source). The app is down from the source stop until the destination serves; a failure before the switch cleans up the destination and restarts the source. source destination routing 1 Review: a dry run shows where,why, the address and downtime. 2 Back up: a final backup of yourdata (final-backup, pull-release). 3 Stop: the source app stops(stop-source). 4 Set up: the new host builds orloads the images, restores data. 5 Start: migrate, start, healthcheck, activate. 6 Switch: routing points at thenew host. 7 Keep: the old copy stays 7 days;a changed address redirects (308). Steps 3 to 6: the app is down. Fails before step 6? The destinationis cleaned up; the source starts again.
A move is reviewed first. The app is down from the source stop until the destination serves; if anything fails before the switch, the source starts again.

Before a move can start

  • The app has a running release, and backup settings, or you tick “This app keeps no data”.
  • Its data is 512 MB or less, the default limit.
  • The destination is approved by an admin and has the same CPU architecture.
  • The destination has another base domain, as an isolated host does, so the platform address changes; a move between two hosts under one base domain needs per-app DNS. Custom domains stay yours: point their DNS at the new host as soon as the move stops the source, because the new host serves the app only once every name resolves to it.
  • A release deployed from an image archive is loaded on the new host, not rebuilt, so that archive must still be kept.

What stays private

Secrets encryptedEnvironment values are encrypted at rest. The API returns their names, never their values.
Values maskedStored values of six or more characters are masked in logs and failed-step output.
Reads recordedOnly you and PitchStation admins can read your logs, and every read is recorded.
Keys left outThe packager leaves .env and key files out of uploads and refuses a file that contains a private key.

Not on the Apps page: creating an app, deploying, rolling back, environment variables and uploading image archives (use the skill, the client or the API), and stopping or deleting an app (the skill or the API).

More: operate · backups and restore · moving to another host · User manual: the Apps page, panel by panel · data, backups and moves

Before stop 01

Apps is switched on per person

Running your own code on shared machines needs more trust than sharing a document, so Apps is never on by default. An admin switches it on for you. Then you make a token for your tools and set up your assistant.

  1. Ask your admin

    They open your account’s Feature access and tick “Deploy hosted apps (containers)”. Until then, the Apps page and the API answer CAPABILITY_REQUIRED.

  2. Create an Apps token

    On the API Tokens page, choose the Apps preset. The token starts with pst_ and is shown once. Keep it in a file, never in a chat or on a command line.

  3. Set up your assistant

    Say the sentence below to Claude Code, Codex or another agent with a shell. Its setup installs the Apps client, which needs Node 20 or later. It never asks you to paste the token into the chat.

Say to your assistantInstall the PitchStation Apps skill: save https://pitchstation.ai/downloads/create-pitchstation-app-SKILL.md as create-pitchstation-app/SKILL.md in your skills folder (~/.claude/skills for Claude Code, ~/.codex/skills for Codex). Then follow its Setup section and tell me which hosts I can deploy to.

Start a new session after installing. Prefer a terminal? The deploy guide shows the same setup by hand.

If your admin requires publisher terms, accept them once on the Apps page while you are signed in.

No PitchStation account yet? Apps is not part of self sign-up. Ask whoever runs PitchStation for your team, or write to hello@pitchstation.ai.

Questions

Can I sign up and start deploying?

Only once an admin has switched Apps on for your account; self sign-up does not include it. Sign in and open the Apps page. If it says CAPABILITY_REQUIRED, ask your admin.

What kinds of projects work?

A project with a Compose file whose settings pass the host’s Compose rules, with images built for the host’s CPU. A Vite and React app (npm), or a Next.js app set to output: 'standalone' (npm or pnpm), is packaged for you without a Compose file.

Do I need Docker on my machine?

Not for a normal deploy: the client uploads your source and the host builds it. You need Docker to build an image archive yourself. The skill also uses Docker for a local smoke test when it is there, and tells you when it is not.

Can I deploy from the Apps page?

No. The Apps page looks after apps that are already deployed: addresses, access, links, backups, moves, budgets, status, logs and operations. Create an app with the skill, the client or the REST API. Deploy with any of those, or with the MCP tools.

Does changing the domain or the password rebuild my app?

No. Address and access changes only re-apply the routing. They never rebuild or restart the app.

What happens to my app if PitchStation is down?

It keeps serving. Passwords, access links, end dates and certificate renewals are handled on the app’s own host. New Sign in with PitchStation sign-ins, deploys and other changes wait until PitchStation is back.

Is my data kept between releases?

Yes, if it lives in named volumes. Files written inside a container’s own file system are lost at the next deploy. Backups add copies on the host and, for backups up to 512 MB, on PitchStation.

Who can read my logs?

You and PitchStation admins. Stored environment values of six or more characters are masked, and every read is recorded in the app’s history.

Will my images run on every host?

Only on a host with the same CPU architecture. An ARM64 host needs ARM64 images. ps-apps targets shows each host’s architecture.

Can someone report an app?

Yes. Anyone can report an app at /abuse.html, without an account. An admin can take an app down; every address then answers 404 until the takedown is lifted.

Next step

Open Apps, or read the manual first

Sign in to see your apps. If the page says CAPABILITY_REQUIRED, your admin has not switched Apps on yet. The manual walks through every stop on this page.

Documentation · Deploy guide · API reference · Architecture · Agent and client setup