Small HTTP API that accepts a ZIP file, extracts it safely, and creates Coolify resources on coolify.mati.ss.
Public deployment: https://uigendeploy.mati.ss
Public docs endpoint: https://uigendeploy.mati.ss/docs
Full API and behavior spec: SPEC.md
TSP generator integration guide: docs/tsp-deployment-api.md
Static HTML ZIPs are the default.
The ZIP must contain already-built browser assets. For Vite/React apps, upload dist/ after npm run build, not the source project. An index.html that references /src/main.tsx, .ts, .tsx, or .jsx entrypoints is rejected because browsers cannot run those files directly from nginx.
When a ZIP contains index.html, the wrapper:
- finds the shallowest
index.html - reads its
<title> - validates that referenced local scripts, stylesheets, module preloads, and favicons exist and are browser-ready
- stores the extracted site under
uploads/static-sites/<title-slug>-<id> - writes a compressed build artifact under
uploads/artifacts - creates a new Coolify Dockerfile application named from that title
- assigns a domain matching
https://<deployment-id>.deploymentsv1.atrium.dubsof.com - serves the site with
nginx
Coolify's API does not currently expose direct static ZIP/file upload. This wrapper uses the closest API-only path: it generates a small Dockerfile that downloads a tokenized static-site artifact from this wrapper during the Coolify build.
cp .env.example .env
npm install
npm startFor local Docker Compose:
docker compose -f docker-compose.yml -f docker-compose.local.yml up --build -ddocker-compose.yml is Coolify-safe and does not publish host port 3000. Coolify should route traffic through its proxy to the container's internal port 3000.
Required Coolify values:
COOLIFY_TOKEN: a Coolify API token from Keys & Tokens. It needs write permissions for create/update/deploy operations.COOLIFY_BASE_URL: defaults tohttps://coolify.mati.ss.COOLIFY_PROJECT_UUIDCOOLIFY_SERVER_UUIDCOOLIFY_ENVIRONMENT_NAMEorCOOLIFY_ENVIRONMENT_UUIDCOOLIFY_DESTINATION_UUID
Optional:
WRAPPER_API_KEY: when set, clients must sendx-api-key: <key>orAuthorization: Bearer <key>.STATIC_SITE_DOMAIN_SUFFIX: deployment domain suffix. Defaults todeploymentsv1.atrium.dubsof.com, so domains are based on the deployment ID, for example12345678-aaaa-bbbb-cccc-123456789abc.deploymentsv1.atrium.dubsof.com.PUBLIC_BASE_URL: public URL used by Coolify builds to download generated artifacts. In production this ishttps://uigendeploy.mati.ss.MAX_STATIC_ARCHIVE_BYTES: compressed static site artifact size limit. Default is26214400.
After setting COOLIFY_TOKEN, run:
curl http://localhost:3000/coolify/discovery \
-H "x-api-key: $WRAPPER_API_KEY"Use:
projects[].uuidforCOOLIFY_PROJECT_UUIDservers[].uuidforCOOLIFY_SERVER_UUIDenvironments[].nameforCOOLIFY_ENVIRONMENT_NAME, usuallyproduction- the Docker network destination UUID from Coolify for
COOLIFY_DESTINATION_UUID
If the destination UUID is not visible in the discovery response, copy it from the Coolify UI when selecting the destination, or from an existing resource configured for that same destination.
Checks the wrapper process.
Public browser-friendly integration docs. This route does not require the wrapper API key.
Related docs endpoints:
GET /docs/api.md: raw deployment API spec.GET /docs/tsp-deployment-api.md: raw TSP generator integration guide.GET /docs/openapi.json: OpenAPI document for client tooling.
Checks Coolify reachability.
Lists projects, servers, resources, and environments visible to the configured token.
Multipart form upload.
Fields:
zip: required.zipfile.manifest: optional JSON object. Overridescoolify.jsoninside the ZIP.
Static HTML example:
curl -X POST http://localhost:3000/deployments \
-H "x-api-key: $WRAPPER_API_KEY" \
-F "zip=@./static-site.zip"If an uploaded ZIP contains index.html, the wrapper treats it as a static HTML artifact and deploys it through Coolify's Dockerfile application API, even if a compose file is also present. Send an explicit manifest with "type": "service" to force the Docker Compose service path.
Response includes:
local.title: title read fromindex.htmllocal.resourceSlug: Coolify resource name derived from the titlelocal.path: extracted copy stored under this projectcoolify: Coolify API response
Uploads a .tsp archive, validates the generated Python backend at services/api, and creates a new Coolify Dockerfile application on port 8080.
curl -X POST https://uigendeploy.mati.ss/tsp-deployments \
-H "x-api-key: $WRAPPER_API_KEY" \
-F "tsp=@./backend.tsp"The generated Dockerfile downloads a tokenized TSP artifact from this wrapper during the Coolify build, installs the generated API package with uv, and starts:
python -m appLegacy archives that use repository/services/api are still accepted as a fallback.
The backend deployment exposes the app internally on port 8080, but the generated Coolify domain uses HTTPS without a port, for example https://<deployment-id>.deploymentsv1.atrium.dubsof.com.
The current generated TSP backend uses SQLite by default. For durable production data, point the generated backend at an external database or adjust the generated backend/container to use persistent storage.
Static HTML ZIPs do not need a manifest. You can still pass one to override Coolify fields:
{
"type": "static-html",
"coolify": {
"project_uuid": "project-uuid",
"server_uuid": "server-uuid",
"environment_name": "production",
"destination_uuid": "destination-uuid",
"domains": "https://custom-id.deploymentsv1.atrium.dubsof.com"
}
}If STATIC_SITE_DOMAIN_SUFFIX=deploymentsv1.atrium.dubsof.com, a deployment ID of 12345678-aaaa-bbbb-cccc-123456789abc becomes:
https://12345678-aaaa-bbbb-cccc-123456789abc.deploymentsv1.atrium.dubsof.com
Docker Compose ZIPs are still supported. If the ZIP contains docker-compose.yml, compose.yml, docker-compose.yaml, or compose.yaml, it creates a Coolify service.
{
"type": "service",
"name": "my-service",
"composeFile": "docker-compose.yml",
"coolify": {
"project_uuid": "project-uuid",
"server_uuid": "server-uuid",
"environment_name": "production",
"destination_uuid": "destination-uuid"
}
}Existing resources can also be redeployed:
{
"type": "deploy",
"uuid": "resource-uuid",
"force": true
}