/SKILL.md
Deploy applications to Coolify via GitHub App. Creates projects, adds public/private GitHub repos, configures subdomains, and triggers deployments. Use when deploying to Coolify, setting up Coolify projects, or automating Coolify infrastructure.
npx skillsauth add adamdavies1915/coolify-deploy coolify-deployInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Deploy any public or private Git repository to Coolify using GitHub App authentication.
Set these environment variables for your Coolify instance:
export COOLIFY_URL="https://coolify.example.com" # Your Coolify instance URL
export COOLIFY_TOKEN='2|your-token-here' # Your Coolify API token
<your-coolify-url>/security/api-tokensCOOLIFY_TOKEN — your API tokenCOOLIFY_URL — your Coolify instance URL (e.g., https://coolify.example.com)Coolify v4 API tokens use a id|hash format, e.g. 2|G0gaUiI5lG3ryJc3.... You must include the full token including the id| prefix in the Authorization: Bearer header. The pipe character (|) is part of the token and must not be stripped.
When storing in shell config:
# Use single quotes to prevent shell interpretation of the pipe
export COOLIFY_TOKEN='2|G0gaUiI5lG3ryJc3nCoWFrj...'
When passing directly in curl, always quote the token to prevent the shell from treating | as a pipe operator.
Ask the user for:
owner/repo)main)https://myapp.example.com)3000)dockerfile, nixpacks, or staticCOOLIFY_URL="${COOLIFY_URL:-https://coolify.example.com}"
# Get API token from user or environment
# COOLIFY_TOKEN should be set
# List GitHub Apps to get the uuid
curl -s -X GET "$COOLIFY_URL/api/v1/github-apps" \
-H "Authorization: Bearer $COOLIFY_TOKEN" | jq '.[] | {uuid, name}'
# List servers
curl -s -X GET "$COOLIFY_URL/api/v1/servers" \
-H "Authorization: Bearer $COOLIFY_TOKEN" | jq '.[] | {uuid, name}'
# List existing projects
curl -s -X GET "$COOLIFY_URL/api/v1/projects" \
-H "Authorization: Bearer $COOLIFY_TOKEN" | jq '.[] | {uuid, name}'
# Create new project
PROJECT_RESPONSE=$(curl -s -X POST "$COOLIFY_URL/api/v1/projects" \
-H "Authorization: Bearer $COOLIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "my-project"}')
PROJECT_UUID=$(echo $PROJECT_RESPONSE | jq -r '.uuid')
This is the main endpoint - deploys any public or private repo via GitHub App:
# Required variables
PROJECT_UUID="your-project-uuid"
SERVER_UUID="your-server-uuid"
GITHUB_APP_UUID="your-github-app-uuid"
GITHUB_REPO="owner/repo-name"
GIT_BRANCH="main"
PORT="3000"
# Create application using private-github-app endpoint
# This works for BOTH public and private repos when using GitHub App auth
APP_RESPONSE=$(curl -s -X POST "$COOLIFY_URL/api/v1/applications/private-github-app" \
-H "Authorization: Bearer $COOLIFY_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"project_uuid\": \"$PROJECT_UUID\",
\"server_uuid\": \"$SERVER_UUID\",
\"github_app_uuid\": \"$GITHUB_APP_UUID\",
\"git_repository\": \"$GITHUB_REPO\",
\"git_branch\": \"$GIT_BRANCH\",
\"build_pack\": \"dockerfile\",
\"ports_exposes\": \"$PORT\",
\"environment_name\": \"production\"
}")
APP_UUID=$(echo $APP_RESPONSE | jq -r '.uuid')
echo "Created application: $APP_UUID"
# Use the full domain provided by the user
APP_DOMAIN="https://myapp.example.com"
curl -s -X PATCH "$COOLIFY_URL/api/v1/applications/$APP_UUID" \
-H "Authorization: Bearer $COOLIFY_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"domains\": \"$APP_DOMAIN\"}"
# Add each env var
curl -s -X POST "$COOLIFY_URL/api/v1/applications/$APP_UUID/envs" \
-H "Authorization: Bearer $COOLIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"key": "NODE_ENV",
"value": "production",
"is_build_time": false
}'
# Trigger deployment
curl -s -X GET "$COOLIFY_URL/api/v1/applications/$APP_UUID/start" \
-H "Authorization: Bearer $COOLIFY_TOKEN"
~/.claude/skills/coolify-deploy/scripts/deploy.sh \
--token "your-api-token" \
--repo "owner/repo" \
--subdomain "myapp" \
--branch "main" \
--port 3000
With environment variable:
export COOLIFY_TOKEN="your-token"
~/.claude/skills/coolify-deploy/scripts/deploy.sh \
--repo "owner/repo" \
--subdomain "myapp"
| Endpoint | Method | Purpose |
|----------|--------|---------|
| /api/v1/projects | POST | Create project |
| /api/v1/projects/{uuid}/environments | GET | List environments |
| /api/v1/servers | GET | List servers |
| /api/v1/github-apps | GET | List GitHub Apps |
| /api/v1/applications/private-github-app | POST | Create app via GitHub App |
| /api/v1/applications/{uuid} | PATCH | Update app (domains, settings) |
| /api/v1/applications/{uuid}/envs | POST | Add environment variable |
| /api/v1/applications/{uuid}/start | GET | Deploy/start application |
For static site generators, use the dockerfile build pack with a multi-stage Dockerfile:
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
Set ports_exposes to 80 (nginx default) and build_pack to dockerfile.
Do NOT use the static build pack -- it has reliability issues with Traefik routing. Do NOT use nixpacks with npx serve as serve may not be available in the runtime.
Important: Always set the domains field when creating/updating an app. If domains is null, Traefik won't route traffic and you'll get 502 Bad Gateway.
<your-coolify-url>/security/api-tokens. Make sure the full id|hash token is being used (see Token Format above).domains is set (not null), ports_exposes matches the port your app actually listens on, and the container is healthy. For static sites, use nginx on port 80 via Dockerfile.dockerfile_location are not accepted by the PATCH endpoint.nixpacks build_packdevops
Local text-to-speech via sherpa-onnx (offline, no cloud)
devops
Feishu cloud storage file management. Activate when user mentions cloud space, folders, drive.
devops
Feishu document read/write operations. Activate when user mentions Feishu docs, cloud docs, or docx links.
devops
Local text-to-speech via sherpa-onnx (offline, no cloud)