Follow these rules and your app will deploy successfully. AI agents: read this page before deploying.
process.env.PORT โ never hardcode a port.process.env.PORT.
Your app must read it. Do NOT use 3000, 8080, or any fixed number.
package.json with a start script.npm start to launch your app. Make sure "scripts": {"start": "node index.js"} exists.
process.env.HOST (always 127.0.0.1). Caddy handles public HTTPS.
process.env.STORAGE_PATH โ never in the code directory.STORAGE_PATH is a per-app persistent
directory that survives all redeploys (removed only when the app is deleted).
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello!'));
app.listen(process.env.PORT, process.env.HOST);
app.listen(3000); // โ hardcoded port โ will crash
The agent zips your code, uploads it, and returns your live URL.
package.json at the root)Choose the ๐ Git URL tab (or tell your agent the repo URL). The server clones the repo โ no upload needed.
| Field | Meaning |
|---|---|
git_url | The repo to clone (HTTPS or SSH) |
git_branch | Optional: which branch to deploy. Leave empty for the repo's default branch |
git_key | Legacy: SSH private key for private SSH repos. Stored encrypted โ later redeploys reuse it. Prefer the deploy-key flow below (no secret sharing) |
Nobody should ever paste an SSH private key or a PAT into a chat. The platform generates the keypair instead:
create_deploy_key (MCP) or POST /api/me/deploy-keys with the repo URLOne key covers all your apps and sites from the same repo. If a deploy hits a private repo before the key is added, the error message already contains the public key and these steps โ follow it and retry.
For private HTTPS repos you can alternatively embed a token in the URL
(https://<token>@github.com/user/repo.git) โ the platform extracts it,
stores it encrypted, and never shows it again.
redeploy_app / POST /api/me/apps/:name/redeploy). The stored
URL, branch, build/start commands, env secrets, and database are all reused.
Connect a repo once โ then every git push to the tracked branch redeploys your app automatically.
application/json (the form-urlencoded default also works)Every webhook is signature-verified (HMAC-SHA256) โ pushes with an invalid signature are rejected with 401. Pushes to other branches do nothing. Pushes that arrive while a deploy is running are queued and collapsed into a single redeploy. Static sites support auto-deploy too (via the API).
Each app has a .env editor (portal app page, or the .env button on the Apps list).
Add secrets once as KEY=value lines โ they are stored encrypted at rest,
survive redeploys (merged by default), and are re-applied to the running process on save.
Agents can use update_app_env (MCP) or PATCH /api/me/apps/:name/env (REST).
APP_BASE_URL from env โ
the platform injects the app's own public HTTPS URL automatically. No manual configuration needed.The platform gives every app a persistent storage directory that no deploy ever touches,
exposed as process.env.STORAGE_PATH. Write uploads there and they survive every redeploy
(the directory is removed only when the app is deleted):
// Express + multer example
const STORAGE = process.env.STORAGE_PATH;
const upload = multer({ dest: STORAGE }); // uploads land in storage
app.post('/api/upload', upload.single('file'), (req, res) => {
db.save({ path: req.file.filename }); // keep names in your DB
res.json({ ok: true });
});
app.use('/uploads', express.static(STORAGE)); // serve them back
// โ https://your-app-url/uploads/<filename>
Students can browse and manage stored files in the portal: app page โ Files โ
Storage tab. One-off commands (run_app_command) also see STORAGE_PATH.
| Framework | start_command | build_command | Notes |
|---|---|---|---|
| Express / plain Node | node index.js | (none) | Simplest โ works out of the box |
| Next.js | next start | npm run build | Must set build_command or it won't compile |
| Nuxt | nuxt start | npm run build | Same as Next.js โ needs build step |
| Static HTML/CSS/JS | (none) | (none) | Deploy as a static site instead โ no server needed |
The platform sets these automatically. Do NOT set them yourself:
| Variable | Value |
|---|---|
PORT | Unique port assigned to your app |
HOST | 127.0.0.1 |
NODE_ENV | production |
DATABASE_URL | Postgres connection string (if a DB is attached) |
APP_BASE_URL | Your app's public HTTPS URL |
STORAGE_PATH | Per-app persistent directory โ survives redeploys. Write uploads here (see below) |
npm, pnpm, and yarn are all installed. The platform detects your lockfile (package-lock.json, pnpm-lock.yaml, or yarn.lock) and uses the right one automatically.
| Problem | Cause | Fix |
|---|---|---|
| App crashes on deploy | Hardcoded port | Use process.env.PORT |
| "package.json not found" | Wrong zip structure | Zip the contents, not a wrapper folder |
| 502 Bad Gateway | App didn't bind its port in 30s | Test npm start locally first |
| Next.js fails | Missing build step | Set build_command: npm run build |
| Uploaded files vanish after redeploy | Files written into the code dir (wiped every deploy) | Write to process.env.STORAGE_PATH |
After deploying, your app is live at:
https://<app-name>-<your-username>.s1.aicc-web.com
AIC-Web Student Hosting Platform ยท Student Portal ยท MCP Auth Spec