원클릭으로
deployment-system
Comprehensive guide to how Docklift builds and deploys user applications.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Comprehensive guide to how Docklift builds and deploys user applications.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | Deployment System |
| description | Comprehensive guide to how Docklift builds and deploys user applications. |
This guide details the lifecycle of a deployment in Docklift, from source code to running container.
routes/projects.ts: Project CRUD, build settings, persistent volumes, domain assignment.routes/deployments.ts: Deployment history plus the streaming deploy / stop / restart / redeploy / cancel handlers.lib/runCompose.ts: Shared docker spawn with mandatory error + close handlers (never leave unhandled spawn errors).lib/deploymentState.ts: In-memory “deploying” lock per project (isProjectDeploying / setProjectDeploying).lib/projectStatusSync.ts: Inspect all service containers; aggregate project status
(running / stopped / error / degraded when some running + some stopped).lib/deploymentRecovery.ts: On boot, mark stale in_progress failed and stuck building projects corrected.lib/portAllocation.ts: Transactional host-port claim (only when publish_host_port is true).services/docker.ts: inspect/logs + connectProxyToProjectNetwork (throws on failure) /
disconnectProxyFromProjectNetwork (before stop/cancel/delete) / teardownProjectNetwork.services/buildResolver.ts: Decides what to build (Dockerfile vs Railpack, base directory, service list).services/buildRunner.ts: Builds image; public build args vs is_secret → BuildKit --secret.services/compose.ts: Scans Dockerfiles (dedupes colliding service names with path hash) and writes
runtime Compose on a per-project network (labels, no-new-privileges, opt-in host ports;
no default cap_drop: ALL / hard mem-cpu caps — optional via compose options).services/git.ts: Clone / pull + scrubOriginRemote.lib/naming.ts: Compose project, container, image, and storageVolumeComposeKey names.Trigger
POST /api/deployments/:projectId/deploy (streaming response).deployment.status = in_progress → 409.
stop / restart also 409 while deploying; caller must cancel first.projects.ts + isProjectDeploying).Preparation
status: in_progress).deployments/<projectId>/:
git clone, or git fetch + reset --hard + clean for an existing checkout.lib/safeUnzip.ts (rejects traversal entries).finally block, even when extraction throws.Git Token Security (GitHub projects):
getInstallationToken().scrubOriginRemote) and verified clean..git/config).spawn / spawnSync with argument arrays — never string interpolation.Build Resolution
build_type on the project is auto (default), dockerfile, or railpack.auto prefers a repository Dockerfile and falls back to Railpack when none is found.base_directory (default .) scopes detection to a monorepo subdirectory. It is resolved
with resolveProjectPath(), which rejects any path escaping the deployment root.dockerfile_path.Image Build (buildServiceImage)
--build-arg only for vars with is_build_arg and not is_secret;
validateDockerBuildArgs() warns when ARG is missing.is_secret → docker buildx build --secret id=KEY,env=KEY (never --build-arg).
Missing RUN --mount=type=secret,id=KEY is a preflight failure (deploy aborts).docker buildx build with plan JSON; build vars as BuildKit secrets + secrets-hash.summarizeBuildFailure(), which turns common toolchain noise into one
actionable line (e.g. an out-of-sync package-lock.json on npm ci).Run
deployments/.docklift/<projectId>/compose.yml.
Source files are never patched — no repository Dockerfile or docker-compose.yml is
rewritten, which means user-committed compose files stay intact.dl-net-<shortId> (not the control-plane docklift_network).publish_host_port === true; otherwise omit ports:.security_opt: no-new-privileges, labels com.docklift.*.
Optional memLimit / cpus via compose options (not applied by default — DB images need room).docker compose -f <runtime-compose> -p <composeProject> up -d --remove-orphansconnectProxyToProjectNetwork(projectId) — on failure mark deploy
failed and do not activate domains (never log false “proxy attached”).disconnectProxyFromProjectNetwork before compose down
(proxy endpoint otherwise blocks network removal). If teardown ultimately fails, reconnect
the proxy so running apps keep domain routing.compose down, verify with exact labels
com.docker.compose.project=<alias> (containers + networks). Never trust stderr “not found”.
Abort delete with 409 if owned resources remain.Verification
syncProjectStatusFromContainers() updates each service from Docker, then aggregates:
all running → running; any error → error; some running + some stopped → degraded;
else stopped. Never report full running for a mixed fleet.setProjectDeploying) is held through status write and nginx/SSL activation.updateMany with status ≠ cancelled so cancel cannot be overwritten as success.failDeploymentState likewise never overwrites cancelled.Cancel (anytime)
compose down OK).in_progress rows cancelled. Idle cancel must not rewrite past
success / failed history.stopped when teardown succeeds.build_type | Behaviour |
|---|---|
auto | Repository Dockerfile if present, else Railpack detection |
dockerfile | Requires a Dockerfile; fails loudly instead of silently falling back |
railpack | Always Railpack, even when a Dockerfile exists |
detectManifests() reports which framework manifests were seen (e.g. package.json,
requirements.txt, pyproject.toml), which is what the UI shows as the detected stack.
Rebuilds replace containers, so anything written to a container's filesystem is lost unless mounted.
PersistentVolume rows
(service_name, mount_path, display_name).dl-<shortId>-<slug>-<hash(label)> so labels like a-b vs a_b never collide.
Labelled com.docklift.project=<projectId> for cleanup.storageVolumeComposeKey(service, index, volumeName).docker compose down never deletes user data.DATABASE_URL need no volume — only in-container state
(SQLite files, uploads, caches) does.All streaming endpoints (deploy, stop, restart, redeploy) use a writeLog helper with a
disconnection guard:
const writeLog = (text: string) => {
try { if (!res.writableEnded) res.write(text); } catch {}
logs.push(text);
};
This prevents crashes when the client disconnects mid-stream and guarantees the deployment status is persisted regardless of connection state.
deployments/
<projectId>/ # Application source (clone/upload root; never modified by Docklift)
.docklift/
<projectId>/
compose.yml # Generated runtime state
*-railpack-*.json # Generated Railpack build plans
.env # Runtime environment variables (when used)
Always use lib/naming.ts — never hand-build these strings.
| Thing | Format | Example |
|---|---|---|
Compose project (-p) | dl-<slug>-<shortId> | dl-python-smoke-53b01966 |
| Container | dl_<slug>_<shortId>_<svc> | dl_python-smoke_53b01966_app |
| Project network | dl-net-<shortId> | dl-net-53b01966 |
| Volume | dl-<shortId>-<slug> | dl-53b01966-data |
shortId is the first 8 hex chars of the project UUID (dashes stripped). composeProjectAliases()
also returns the bare project UUID, the legacy compose project name, so older deployments can still
be torn down.
Control plane (docklift-*) → docklift_network. User apps → per-project dl-net-* only
(proxy attached after up).
isValidEnvKey; unique (project_id, key) after startup/prepareDb dedupe.docker logs <container>.internal_port.POST /:projectId/cancel first.in_progress / building after backend restart: recoverDeploymentStateOnBoot() marks
interrupted deployments failed and reconciles project status from containers.Guide for server management, system APIs, backups, and maintenance operations.
Guide for developing features in the Vite + React Router frontend.
Guide to Docklift's automated release pipeline using semantic-release.
Guide for setting up, running, and developing the Docklift project.
Guide for setting up and managing Docklift's GitHub App integration.
Coolify/Dokploy-style managed databases with Dokku-style app linking.