Yuki Deploy docs
Yuki Deploy builds your code into a container and runs it at name.deploy.yukichat.lol with its own HTTPS certificate. You sign in with YukiChat.
Quick start
# 1. install the CLI (macOS, Linux, WSL) curl -fsSL deploy.yukichat.lol/install | sh # 2. log in: approve the code in your browser yd login # 3. deploy from your project folder cd my-app yd
The first yd asks for a name and saves it in .yukideploy, so the next deploys go to the same app. You can also upload a .zip or import a Git repo from the dashboard.
The one rule: your app must listen on 0.0.0.0 at the port in $PORT (8080 unless you change it). localhost won't be reachable.
CLI
| Command | What it does |
|---|---|
yd [folder] | Pack the folder (skipping node_modules, .git, .env, virtualenvs) and deploy it. Follows the build log. |
yd ls | Your apps and their state. |
yd logs [-f] [--tail N] | App output; -f keeps following. |
yd env · set K=V · rm K | Environment variables. REVEAL=1 yd env prints values. |
yd restart | stop | start | Control the running container. |
yd rollback | Put the previous build back live (no rebuild). |
yd git <url> [branch] | Build from a public Git repo instead of local files. |
yd open · yd rm | Open the app, or delete it with its data. |
Every command takes --name <app>. Add a .ydignore (tar exclude patterns, one per line) to skip more files. In CI, set YD_TOKEN to an API token from the dashboard menu.
Runtimes
If there's no Dockerfile, the stack is detected from the files at the root:
| Found | Build | Start |
|---|---|---|
Dockerfile | Your Dockerfile | Its CMD. Port from EXPOSE, else 8080. |
package.json | Node 20: npm ci / pnpm / yarn by lockfile, then the build script | start script, else main/server.js/index.js. No server at all? The build output (dist, build, out) is served as a static SPA. |
requirements.txt / pyproject.toml | Python 3.12, pip install | FastAPI → uvicorn main:app, Flask → gunicorn app:app, Django → gunicorn project.wsgi, else python main.py. A Procfile web: line wins. |
index.html | none | Static files. For static-only sites, Yuki Pages is lighter. |
yuki.json
Optional, at the project root. Every field is optional:
{
"runtime": "node", // node | python | static | docker
"build": "npm run build:prod",
"start": "node dist/server.js",
"port": 3000
}
The start command and port can also be set in the dashboard under Settings → Advanced.
Env vars and /data
Set variables in the dashboard or with yd env set. They apply on the next deploy or restart. These are always set: PORT, YUKI_APP (the app name) and YUKI_URL (its public URL).
/data is a disk that survives deploys and restarts (512 MB). Put SQLite files and uploads there; everything else in the container resets on each deploy.
Sleep and wake
When an app gets no requests for its sleep time (15 minutes by default), its container stops. The next request starts it again and waits until it answers, usually one or two seconds. Background jobs and bots that only poll stop while asleep. If an app crashes on start, visitors see a "crashed" page and the logs show why.
Deploys swap with no downtime: the new container must answer HTTP within 60 seconds before traffic moves to it. If it doesn't, the old one stays live and the deploy is marked failed.
Git and webhooks
Connect a public https repo (GitHub, GitLab, Codeberg…) when you create the app or in Settings. The dashboard then shows a webhook URL. In GitHub: Settings → Webhooks → Add webhook, paste it as the Payload URL, pick application/json and "Just the push event". Pushes to other branches are ignored.
HTTP API
Base URL https://deploy.yukichat.lol. Send Authorization: Bearer yd_… (a token from the dashboard menu or yd login). Errors come back as {"detail": "…"}.
| Request | What it does |
|---|---|
GET /api/me | You, your apps and your limits |
POST /api/apps | {"name", "git_url"?, "git_branch"?}, creates the app (and builds when there's a repo) |
GET /api/apps/{name} | One app: state, URL, settings |
PATCH /api/apps/{name} | memory, sleep_min, start_cmd, app_port, git_url, git_branch, new_hook |
DELETE /api/apps/{name} | Delete the app, its images and /data |
POST /api/apps/{name}/deploy | Body: a .tar.gz or .zip (any content type), or JSON {"git_url"?, "git_branch"?}. ?create=1 makes the app if needed, ?message= labels it. Returns {"id"}. |
GET /api/apps/{name}/deployments | Last 30 deployments |
GET /api/deployments/{id}?offset=N | Status and build log from byte N. Poll with the returned offset. &fmt=text gives plain text with X-Status/X-Offset headers. |
POST /api/apps/{name}/rollback | {"deployment": id}, reuses that build's image |
POST /api/apps/{name}/restart|stop|start | Container control |
GET /api/apps/{name}/logs?tail=300 | App output (plain text) |
GET /api/apps/{name}/stats | CPU, memory, network of the running container |
GET|PUT /api/apps/{name}/env | PUT {"set": {K: V}, "unset": [K]} or {"env": {…}} to replace all |
POST /api/hooks/{name}/{key} | Push webhook (no token; the key is the secret) |
# deploy a folder from CI
tar -czf app.tar.gz --exclude=node_modules --exclude=.git .
curl -fsS -X POST -H "Authorization: Bearer $YD_TOKEN" \
--data-binary @app.tar.gz \
"https://deploy.yukichat.lol/api/apps/my-app/deploy?message=ci"
Limits
| What | Limit |
|---|---|
| Apps per account | 3 |
| Memory | 128 or 256 MB, 0.5 CPU |
| Sleep after idle | 5–60 minutes |
| Build | 10 minutes, 1 GB memory, one build at a time on the server (others queue) |
| Upload | 50 MB packed, 250 MB / 20,000 files unpacked |
| Image | 1.5 GB |
| /data | 512 MB (the app is paused when it's over) |
| Network | Outbound internet only: no host, private ranges, other apps or port 25 |
Phishing, crypto miners, spam, proxies for abuse and anything illegal get disabled without notice.