coolify-client.ts•19.9 kB
/**
* Coolify API Client
* Provides methods to interact with Coolify Self-hosted instances
* Reference: https://coolify.io/docs/api
*/
import axios, { AxiosInstance } from 'axios';
import {
CoolifyConfig,
CoolifyApiResponse,
Application,
EnvironmentVariable,
DeploymentStatus,
Domain,
Server,
Team,
Service,
LogEntry,
DocumentationEntry,
DocumentationSearchResult
} from '../types/coolify';
export class CoolifyApiClient {
private client: AxiosInstance;
constructor(config: CoolifyConfig) {
// Create axios instance with base configuration
this.client = axios.create({
baseURL: `${config.baseUrl}/api/v1`,
headers: {
'Authorization': `Bearer ${config.apiToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
timeout: 30000, // 30 seconds timeout
});
// Add response interceptor for error handling
this.client.interceptors.response.use(
(response) => response,
(error) => {
console.error('Coolify API Error:', error.response?.data || error.message);
throw error;
}
);
}
/**
* Test API connection and health
*/
async testConnection(): Promise<boolean> {
try {
const response = await this.client.get('/health');
return response.status === 200;
} catch (error) {
console.error('Connection test failed:', error);
return false;
}
}
/**
* Get all applications
*/
async getApplications(): Promise<Application[]> {
const response = await this.client.get<CoolifyApiResponse<Application[]>>('/applications');
return response.data.data || [];
}
/**
* Get specific application by ID
*/
async getApplication(applicationId: string): Promise<Application> {
const response = await this.client.get<CoolifyApiResponse<Application>>(`/applications/${applicationId}`);
if (!response.data.data) {
throw new Error(`Application ${applicationId} not found`);
}
return response.data.data;
}
/**
* Deploy an application
*/
async deployApplication(applicationId: string, options?: { force?: boolean; branch?: string }): Promise<DeploymentStatus> {
const payload: any = {};
if (options?.force) payload.force = true;
if (options?.branch) payload.branch = options.branch;
const response = await this.client.post<CoolifyApiResponse<DeploymentStatus>>(
`/applications/${applicationId}/deploy`,
payload
);
if (!response.data.data) {
throw new Error(`Failed to deploy application ${applicationId}`);
}
return response.data.data;
}
/**
* Get application deployment status
*/
async getApplicationStatus(applicationId: string): Promise<DeploymentStatus> {
const response = await this.client.get<CoolifyApiResponse<DeploymentStatus>>(
`/applications/${applicationId}/status`
);
if (!response.data.data) {
throw new Error(`Failed to get status for application ${applicationId}`);
}
return response.data.data;
}
/**
* Stop an application
*/
async stopApplication(applicationId: string): Promise<boolean> {
const response = await this.client.post(`/applications/${applicationId}/stop`);
return response.status === 200;
}
/**
* Start an application
*/
async startApplication(applicationId: string): Promise<boolean> {
const response = await this.client.post(`/applications/${applicationId}/start`);
return response.status === 200;
}
/**
* Restart an application
*/
async restartApplication(applicationId: string): Promise<boolean> {
const response = await this.client.post(`/applications/${applicationId}/restart`);
return response.status === 200;
}
/**
* Update environment variables for an application
*/
async updateEnvironmentVariables(applicationId: string, variables: EnvironmentVariable[]): Promise<boolean> {
const response = await this.client.put(
`/applications/${applicationId}/environment-variables`,
{ variables }
);
return response.status === 200;
}
/**
* Get environment variables for an application
*/
async getEnvironmentVariables(applicationId: string): Promise<EnvironmentVariable[]> {
const response = await this.client.get<CoolifyApiResponse<EnvironmentVariable[]>>(
`/applications/${applicationId}/environment-variables`
);
return response.data.data || [];
}
/**
* Set domain for an application
*/
async setDomain(applicationId: string, domain: string, enableHttps: boolean = true): Promise<Domain> {
const response = await this.client.post<CoolifyApiResponse<Domain>>(
`/applications/${applicationId}/domains`,
{ domain, https: enableHttps }
);
if (!response.data.data) {
throw new Error(`Failed to set domain for application ${applicationId}`);
}
return response.data.data;
}
/**
* Get application logs
*/
async getApplicationLogs(applicationId: string, lines: number = 100, since?: string): Promise<LogEntry[]> {
const params: any = { lines };
if (since) params.since = since;
const response = await this.client.get<CoolifyApiResponse<LogEntry[]>>(
`/applications/${applicationId}/logs`,
{ params }
);
return response.data.data || [];
}
/**
* Create a new application
*/
async createApplication(application: Partial<Application>): Promise<Application> {
const response = await this.client.post<CoolifyApiResponse<Application>>(
'/applications',
application
);
if (!response.data.data) {
throw new Error('Failed to create application');
}
return response.data.data;
}
/**
* Delete an application
*/
async deleteApplication(applicationId: string): Promise<boolean> {
const response = await this.client.delete(`/applications/${applicationId}`);
return response.status === 200;
}
/**
* Get all servers
*/
async getServers(): Promise<Server[]> {
const response = await this.client.get<CoolifyApiResponse<Server[]>>('/servers');
return response.data.data || [];
}
/**
* Get all teams
*/
async getTeams(): Promise<Team[]> {
const response = await this.client.get<CoolifyApiResponse<Team[]>>('/teams');
return response.data.data || [];
}
/**
* Get all services
*/
async getServices(): Promise<Service[]> {
const response = await this.client.get<CoolifyApiResponse<Service[]>>('/services');
return response.data.data || [];
}
/**
* Get documentation for a specific topic
*/
async getDocumentation(topic: string, category?: string): Promise<DocumentationEntry[]> {
// This is a mock implementation. In a real scenario, you would either:
// 1. Fetch from Coolify's internal documentation API (if available)
// 2. Maintain a local documentation database
// 3. Fetch from external documentation sources
const docs = this.getBuiltInDocumentation();
let filtered = docs.filter(doc =>
doc.title.toLowerCase().includes(topic.toLowerCase()) ||
doc.content.toLowerCase().includes(topic.toLowerCase()) ||
doc.tags.some(tag => tag.toLowerCase().includes(topic.toLowerCase()))
);
if (category) {
filtered = filtered.filter(doc => doc.category === category);
}
return filtered;
}
/**
* Search documentation
*/
async searchDocumentation(query: string, category?: string, limit: number = 10): Promise<DocumentationSearchResult> {
const docs = await this.getDocumentation(query, category);
return {
entries: docs.slice(0, limit),
total: docs.length,
query: query
};
}
/**
* Get API reference documentation
*/
async getApiReference(endpoint?: string): Promise<DocumentationEntry[]> {
const docs = this.getBuiltInDocumentation();
let apiDocs = docs.filter(doc => doc.category === 'api');
if (endpoint) {
apiDocs = apiDocs.filter(doc =>
doc.content.toLowerCase().includes(endpoint.toLowerCase()) ||
doc.title.toLowerCase().includes(endpoint.toLowerCase())
);
}
return apiDocs;
}
/**
* Get troubleshooting documentation
*/
async getTroubleshooting(issue: string): Promise<DocumentationEntry[]> {
const docs = this.getBuiltInDocumentation();
return docs.filter(doc =>
doc.category === 'troubleshooting' &&
(doc.title.toLowerCase().includes(issue.toLowerCase()) ||
doc.content.toLowerCase().includes(issue.toLowerCase()) ||
doc.tags.some(tag => tag.toLowerCase().includes(issue.toLowerCase())))
);
}
/**
* Built-in documentation database
* This contains essential Coolify documentation for common tasks
*/
private getBuiltInDocumentation(): DocumentationEntry[] {
return [
// API Documentation
{
id: 'api-authentication',
title: 'API Authentication',
category: 'api',
tags: ['api', 'authentication', 'token', 'bearer'],
content: `# API Authentication
To authenticate with the Coolify API, you need to include a Bearer token in your requests:
## Header Format
\`\`\`
Authorization: Bearer <your-api-token>
\`\`\`
## Getting an API Token
1. Go to your Coolify dashboard
2. Navigate to Settings → Keys & Tokens → API Tokens
3. Click "Create New Token"
4. Define a name for your token
5. Select appropriate permissions:
- \`read-only\`: Read data only
- \`read:sensitive\`: Read including sensitive data
- \`*\`: Full access (recommended for automation)
## Token Scopes
- Tokens are scoped to the team that created them
- Each token has specific permissions
- Tokens are shown only once upon creation
## API Endpoints
- Base URL: \`http://<your-coolify-instance>/api/v1\`
- Health check: \`/health\` (no authentication required)`,
url: 'https://coolify.io/docs/api'
},
{
id: 'api-applications',
title: 'Applications API',
category: 'api',
tags: ['api', 'applications', 'deploy', 'manage'],
content: `# Applications API
## List Applications
\`GET /applications\`
Returns all applications accessible to your token.
## Get Application
\`GET /applications/{id}\`
Returns detailed information about a specific application.
## Deploy Application
\`POST /applications/{id}/deploy\`
Triggers a new deployment. Optional parameters:
- \`force\`: boolean - Force deployment even if another is in progress
- \`branch\`: string - Deploy specific git branch
## Start/Stop/Restart Application
- \`POST /applications/{id}/start\`
- \`POST /applications/{id}/stop\`
- \`POST /applications/{id}/restart\`
## Environment Variables
- \`GET /applications/{id}/environment-variables\`
- \`PUT /applications/{id}/environment-variables\`
## Logs
\`GET /applications/{id}/logs?lines=100&since=2024-01-01T00:00:00Z\``,
url: 'https://coolify.io/docs/api'
},
// Deployment Guides
{
id: 'guide-deployment',
title: 'Application Deployment Guide',
category: 'guide',
tags: ['deployment', 'guide', 'getting-started', 'applications'],
content: `# Application Deployment Guide
## Prerequisites
1. Coolify instance running
2. Server connected to Coolify
3. Git repository accessible
4. Domain configured (optional)
## Step-by-Step Deployment
### 1. Create Application
1. Go to Projects → Create New Application
2. Select deployment method:
- Git Repository
- Docker Image
- Docker Compose
### 2. Configure Repository
- Repository URL
- Branch (default: main)
- Build pack (Nixpacks, Dockerfile, etc.)
### 3. Environment Variables
Set necessary environment variables:
- Database connections
- API keys
- Application settings
### 4. Domain Configuration
- Set FQDN (Fully Qualified Domain Name)
- Enable HTTPS/SSL (recommended)
- Configure custom domains
### 5. Deploy
Click "Deploy" to start the deployment process
## Build Packs
- **Nixpacks**: Auto-detects and builds most applications
- **Dockerfile**: Uses your custom Dockerfile
- **Docker Compose**: For multi-service applications`,
url: 'https://coolify.io/docs/applications'
},
{
id: 'guide-environment-variables',
title: 'Environment Variables Guide',
category: 'guide',
tags: ['environment', 'variables', 'configuration', 'secrets'],
content: `# Environment Variables Guide
## Predefined Variables
Coolify automatically provides these variables:
- \`COOLIFY_FQDN\`: Application's domain name
- \`COOLIFY_URL\`: Application's URL(s)
- \`COOLIFY_CONTAINER_NAME\`: Container name
- \`COOLIFY_RESOURCE_UUID\`: Unique resource ID
- \`SOURCE_COMMIT\`: Git commit hash
- \`PORT\`: Application port (defaults to first exposed port)
- \`HOST\`: Defaults to 0.0.0.0
## Custom Variables
Set custom environment variables for your application:
### Build-time Variables
Available during the build process:
- \`NODE_ENV=production\`
- \`API_URL=https://api.example.com\`
### Runtime Variables
Available when the application runs:
- \`DATABASE_URL=postgresql://...\`
- \`REDIS_URL=redis://...\`
### Sensitive Variables
Mark variables as sensitive to hide them in the UI:
- API keys
- Passwords
- Tokens
## Usage Example
\`\`\`bash
# Use predefined variables
MY_VARIABLE=$SOURCE_COMMIT
# Database configuration
DB_CONNECTION=postgresql
DB_HOST=postgres.example.com
DB_PORT=5432
DB_DATABASE=myapp
DB_USERNAME=user
DB_PASSWORD=secret
\`\`\``,
url: 'https://coolify.io/docs/knowledge-base/environment-variables'
},
// Configuration
{
id: 'config-domains-ssl',
title: 'Domain and SSL Configuration',
category: 'configuration',
tags: ['domain', 'ssl', 'https', 'certificates'],
content: `# Domain and SSL Configuration
## Setting Up Domains
### 1. Configure FQDN
Set the Fully Qualified Domain Name for your application:
- \`app.yourdomain.com\`
- \`subdomain.example.org\`
### 2. DNS Configuration
Point your domain to your server:
- A record: \`app.yourdomain.com → 1.2.3.4\`
- CNAME record: \`app.yourdomain.com → your-server.example.com\`
### 3. SSL/HTTPS Setup
Coolify automatically handles SSL certificates using Let's Encrypt:
#### Automatic SSL
- Enable HTTPS in application settings
- Coolify requests Let's Encrypt certificate
- Auto-renewal handled automatically
#### Custom Certificates
Upload your own SSL certificates:
1. Go to application settings
2. Upload certificate files
3. Configure SSL settings
## Wildcard Certificates
For multiple subdomains:
\`\`\`
*.yourdomain.com
\`\`\`
## Traefik Configuration
Coolify uses Traefik as reverse proxy:
- Automatic SSL termination
- Load balancing
- Request routing`,
url: 'https://coolify.io/docs/knowledge-base'
},
// Troubleshooting
{
id: 'troubleshoot-deployment-failed',
title: 'Deployment Failed',
category: 'troubleshooting',
tags: ['deployment', 'failed', 'build', 'error'],
content: `# Troubleshooting: Deployment Failed
## Common Causes and Solutions
### 1. Build Errors
**Symptoms**: Build process fails, error in build logs
**Solutions**:
- Check build logs for specific errors
- Verify dependencies in package.json/requirements.txt
- Ensure correct Node.js/Python version
- Check for syntax errors in code
### 2. Port Configuration
**Symptoms**: Application builds but not accessible
**Solutions**:
- Verify application listens on correct port
- Use \`PORT\` environment variable: \`app.listen(process.env.PORT || 3000)\`
- Check if port is exposed in Dockerfile
### 3. Environment Variables
**Symptoms**: Application crashes or behaves unexpectedly
**Solutions**:
- Verify all required environment variables are set
- Check for typos in variable names
- Ensure sensitive variables are properly configured
### 4. Memory/Resource Limits
**Symptoms**: Build process killed, out of memory errors
**Solutions**:
- Increase server resources
- Optimize build process
- Use multi-stage Docker builds
- Clear build cache
### 5. Git Repository Issues
**Symptoms**: Cannot clone repository, authentication errors
**Solutions**:
- Verify repository URL
- Check deploy key permissions
- Ensure repository is accessible
- Verify branch name`,
url: 'https://coolify.io/docs/knowledge-base'
},
{
id: 'troubleshoot-ssl-issues',
title: 'SSL Certificate Issues',
category: 'troubleshooting',
tags: ['ssl', 'certificate', 'https', 'letsencrypt'],
content: `# Troubleshooting: SSL Certificate Issues
## Common SSL Problems
### 1. Let's Encrypt Rate Limits
**Symptoms**: Certificate generation fails, rate limit errors
**Solutions**:
- Wait for rate limit reset (1 week for duplicate certificates)
- Use staging environment for testing
- Check Let's Encrypt status page
### 2. Domain Verification Failed
**Symptoms**: Certificate cannot be issued, domain verification fails
**Solutions**:
- Verify DNS records point to correct server
- Check domain is accessible via HTTP first
- Ensure port 80 is open and accessible
- Wait for DNS propagation (up to 48 hours)
### 3. Certificate Renewal Issues
**Symptoms**: Certificate expires, renewal fails
**Solutions**:
- Check Coolify logs for renewal errors
- Verify domain still points to server
- Manually trigger certificate renewal
- Check server disk space
### 4. Mixed Content Warnings
**Symptoms**: Browser warnings, some content not secure
**Solutions**:
- Ensure all resources use HTTPS URLs
- Update API endpoints to use HTTPS
- Check for hardcoded HTTP links in code
### 5. Certificate Chain Issues
**Symptoms**: Browser shows certificate errors
**Solutions**:
- Use SSL checker tools to verify certificate chain
- Check intermediate certificates
- Contact certificate provider`,
url: 'https://coolify.io/docs/knowledge-base'
}
];
}
/**
* Get available documentation topics
*/
async getDocumentationTopics(): Promise<DocumentationEntry[]> {
// Return available documentation topics
return [
{
id: 'getting-started',
title: 'Getting Started',
content: 'Learn the basics of Coolify',
category: 'guide',
tags: ['basics', 'introduction'],
url: 'https://coolify.io/docs/getting-started'
},
{
id: 'applications',
title: 'Applications',
content: 'Deploy and manage applications',
category: 'guide',
tags: ['deploy', 'apps'],
url: 'https://coolify.io/docs/applications'
},
{
id: 'databases',
title: 'Databases',
content: 'Deploy and manage databases',
category: 'guide',
tags: ['database', 'mysql', 'postgresql'],
url: 'https://coolify.io/docs/databases'
},
{
id: 'environment-variables',
title: 'Environment Variables',
content: 'Configure environment variables',
category: 'configuration',
tags: ['env', 'config'],
url: 'https://coolify.io/docs/environment-variables'
},
{
id: 'domains',
title: 'Custom Domains',
content: 'Set up custom domains and SSL',
category: 'configuration',
tags: ['domain', 'ssl', 'https'],
url: 'https://coolify.io/docs/domains'
},
{
id: 'api-reference',
title: 'API Reference',
content: 'Complete API documentation',
category: 'api',
tags: ['api', 'reference'],
url: 'https://coolify.io/docs/api'
},
{
id: 'troubleshooting',
title: 'Troubleshooting',
content: 'Common issues and solutions',
category: 'troubleshooting',
tags: ['debug', 'issues', 'help'],
url: 'https://coolify.io/docs/troubleshooting'
}
];
}
}