Back to Coolify Series
    Part 2 of 6

    Deploying Your First Application

    Deploy three progressively complex applications: a static site, a Node.js app, and a Python Flask API. Learn how Coolify handles builds, environment variables, and automatic SSL.

    Hands-On
    Git Integration
    ⏱️ 20 min
    1

    Connecting Your Git Provider

    Coolify can pull code directly from GitHub, GitLab, Bitbucket, or any Git repository. Let's connect GitHub first—it's the most common setup.

    🔗 Option 1: GitHub App (Recommended)

    The GitHub App integration gives you the smoothest experience with automatic webhooks and fine-grained permissions.

    1. In Coolify, go to SourcesAdd SourceGitHub App
    2. Click Register GitHub App
    3. You'll be redirected to GitHub to create and install the app
    4. Choose which repositories Coolify can access (all or selected)
    5. Authorize and return to Coolify

    When you push to any authorized repository, Coolify will automatically trigger a deployment.

    🔑 Option 2: Deploy Key (Public Repos)

    For quick tests or public repositories:

    1. Go to SourcesAdd SourcePublic Repository
    2. Paste the repository URL (e.g., https://github.com/username/repo)

    This method doesn't support automatic deployments—you'll trigger builds manually or via API.

    🔄 Option 3: GitLab / Bitbucket

    The process is similar for other providers:

    1. Go to SourcesAdd SourceGitLab (or Bitbucket)
    2. Follow the OAuth flow to connect your account
    3. Select repositories to authorize
    2

    Your First Deploy: A Static Site

    Let's start with something simple—a static HTML/CSS site. This takes about two minutes and validates your entire setup.

    Create a Test Repository

    If you don't have a static site ready, create a quick one:

    Initialize repository
    mkdir my-static-site && cd my-static-site
    git init
    index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Deployed with Coolify</title>
        <style>
            body {
                font-family: system-ui, sans-serif;
                max-width: 600px;
                margin: 100px auto;
                padding: 20px;
                text-align: center;
            }
            h1 { color: #6b46c1; }
        </style>
    </head>
    <body>
        <h1>Hello from Coolify! 🚀</h1>
        <p>Deployed on RamNode infrastructure.</p>
    </body>
    </html>
    Push to GitHub
    git add .
    git commit -m "Initial commit"
    gh repo create my-static-site --public --push

    Deploy in Coolify

    1. Go to ProjectsAdd Project → Give it a name (e.g., "My Sites")
    2. Inside the project, click Add ResourcePublic Repository
    3. Paste your repository URL or select it from the list
    4. Coolify auto-detects it as a Static site
    SettingValue
    Build PackStatic
    Base Directory/ (or where your index.html lives)
    Publish Directory/ (same for simple sites)

    Click Deploy and watch the build logs. For a static site, this takes 10-30 seconds.

    Automatic Deployments: If you used the GitHub App, push a change and Coolify will automatically redeploy within seconds. Zero configuration required.

    3

    Deploying a Node.js Application

    Now let's deploy something with a build step and runtime—a simple Express API.

    Sample Express App

    package.json
    {
      "name": "my-node-api",
      "version": "1.0.0",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "dependencies": {
        "express": "^4.18.2"
      }
    }
    index.js
    const express = require('express');
    const app = express();
    const port = process.env.PORT || 3000;
    
    app.get('/', (req, res) => {
      res.json({
        message: 'Hello from Coolify!',
        environment: process.env.NODE_ENV || 'development',
        timestamp: new Date().toISOString()
      });
    });
    
    app.get('/health', (req, res) => {
      res.json({ status: 'healthy' });
    });
    
    app.listen(port, '0.0.0.0', () => {
      console.log(`API running on port ${port}`);
    });
    .gitignore
    node_modules/
    .env

    Configure the Node.js Build

    Coolify auto-detects Node.js from your package.json. Verify these settings:

    SettingValue
    Build PackNixpacks (auto-detected)
    Port3000
    Start Commandnpm start (auto-detected)

    Understanding Nixpacks: Coolify uses Nixpacks by default—an intelligent build system that analyzes your code and generates an optimized container. It detects your runtime, installs dependencies, and configures the start command automatically. No Dockerfile needed.

    4

    Environment Variables

    Most real applications need configuration—API keys, database URLs, feature flags. Coolify handles these securely.

    In your resource settings, find the Environment Variables section:

    Environment Variables
    NODE_ENV=production
    API_KEY=your-secret-key
    DATABASE_URL=postgres://user:pass@host:5432/db

    Variables are encrypted at rest, injected at runtime (not baked into images), and available during build if marked as "Build Variable".

    Build vs Runtime Variables

    TypeWhen AvailableUse Case
    RuntimeApp execution onlyAPI keys, database URLs, secrets
    BuildDuring npm install, etc.Private npm tokens, build-time configs
    5

    Deploying a Python Flask API

    Let's add a Python application to see how Coolify handles different runtimes.

    requirements.txt
    flask==3.0.0
    gunicorn==21.2.0
    app.py
    import os
    from flask import Flask, jsonify
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello():
        return jsonify({
            'message': 'Hello from Flask on Coolify!',
            'environment': os.environ.get('FLASK_ENV', 'development')
        })
    
    @app.route('/health')
    def health():
        return jsonify({'status': 'healthy'})
    
    if __name__ == '__main__':
        port = int(os.environ.get('PORT', 5000))
        app.run(host='0.0.0.0', port=port)

    Configure the Flask Build

    SettingValue
    Build PackNixpacks
    Port5000
    Start Commandgunicorn app:app --bind 0.0.0.0:$PORT

    Important: Nixpacks might default to python app.py. For production, override the start command to use Gunicorn (a production WSGI server).

    6

    Build Packs: Nixpacks vs Dockerfile

    Coolify offers multiple ways to build your applications:

    🚀 Nixpacks (Default)

    Best for standard applications in common languages. Supports Node.js, Python, Go, Rust, Ruby, PHP, Java, and more.

    Pros:

    • Zero configuration for most apps
    • Optimized caching and layer reuse
    • Automatic security updates

    Cons:

    • Less control over build environment
    • May not support niche dependencies

    🐳 Dockerfile

    Best for custom requirements, specific base images, complex builds.

    Example Dockerfile
    FROM node:20-alpine
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci --only=production
    COPY . .
    EXPOSE 3000
    CMD ["node", "index.js"]

    To force Dockerfile builds, set Build Pack to Dockerfile in your resource settings.

    📦 Docker Compose

    Best for multi-container applications. Coolify can deploy entire stacks defined in docker-compose.yml files—covered in Part 4.

    7

    Custom Domains and SSL

    Every app deployed on Coolify gets a random subdomain by default. Let's configure a proper domain.

    Add a Custom Domain

    1. In your resource settings, find Domains
    2. Add your domain: api.yourdomain.com
    3. Save

    Configure DNS

    Add an A record pointing to your Coolify server:

    DNS Record
    Type: A
    Name: api
    Value: your-coolify-server-ip
    TTL: 300

    Automatic SSL: Once DNS propagates (usually 1-5 minutes), Coolify automatically provisions a Let's Encrypt certificate. You'll see the lock icon appear in your browser.

    Wildcard SSL

    If you configured a wildcard domain in Part 1 (e.g., *.apps.yourdomain.com), any app can use subdomains without additional DNS records:

    • my-api.apps.yourdomain.com
    • staging.apps.yourdomain.com
    • client-demo.apps.yourdomain.com
    8

    Deployment Settings Deep Dive

    Health Checks

    Coolify can verify your app is running before routing traffic:

    SettingRecommended Value
    Health Check Path/health
    Health Check Interval30 seconds
    Health Check Timeout5 seconds

    Resource Limits

    Prevent runaway apps from consuming your entire server:

    App SizeMemoryCPU
    Small apps256M0.5
    Medium apps512M1
    Large apps1G+2

    Persistent Storage

    By default, container storage is ephemeral. For apps that need to persist files:

    1. Go to Persistent Storage in resource settings
    2. Add a volume: Source /data/my-app/uploads → Destination /app/uploads
    9

    Monitoring Your Deployments

    📋 Build Logs

    Every deployment shows real-time build logs. Common issues:

    • Dependency failures: Check package.json or requirements.txt for typos
    • Port mismatch: Ensure your app listens on the expected port
    • Missing env vars: Build-time failures often indicate missing config

    📝 Application Logs

    For runtime issues, check Logs in your resource view. This streams stdout and stderr from your container.

    Quick Debugging

    SSH into your server and inspect directly:

    Debug commands
    # List running containers
    docker ps
    
    # View logs for a specific app
    docker logs <container-id> --tail 100 -f
    
    # Shell into a container
    docker exec -it <container-id> /bin/sh
    10

    Rollbacks

    Coolify keeps your previous deployments. If something breaks:

    1. Go to Deployments in your resource
    2. Find a working previous deployment
    3. Click Rollback

    Traffic switches back to the previous version within seconds. No downtime, no stress.

    What's Next

    You've now deployed three different types of applications with custom domains, environment variables, and automatic SSL. Your self-hosted PaaS is doing real work.

    In Part 3, we'll add databases to the mix—spinning up PostgreSQL, MySQL, and Redis instances, connecting them to your apps, and setting up automated backups.