Skip to content

Adding a New Application to PLift

This guide explains how to add your own application/repository under an existing framework in PLift.

Overview

When adding a new app, PLift will: 1. Generate a Dockerfile for your app 2. Create environment configuration files (.env, application.properties, etc.) 3. Set up database connections and migrations 4. Configure monitoring (Prometheus, OpenTelemetry, logging) 5. Add routing to HAProxy 6. Generate SSL certificates

Prerequisites

  • Your application code in the apps/ directory or a Git repository
  • PLift base stack running (plift start-base)
  • Understanding of your app's requirements (database, ports, dependencies)

Step-by-Step Guide

Step 1: Prepare Your Application

Option A: Local Application Directory

Place your application in the apps/ directory:

# Example: Copy your Laravel app
cp -r /path/to/my-laravel-app apps/my_laravel_app

# Or clone from Git
git clone https://github.com/yourusername/my-app.git apps/my_app

PLift can clone your repository automatically. Just provide the Git URL in the configuration.

Step 2: Edit Application Configuration

Edit configs/apps/init.sls and add your application under the appropriate framework section.

Example: Adding a Laravel Application

{% set local_domain = salt['environ.get']('LOCAL_DOMAIN', 'plift.local') %}
plift:
  apps:
    laravel:
      # Existing example app
      example_laravel:
        # ... existing config ...

      # Your new Laravel app
      my_laravel_app:
        # Load balancer URL (required for HAProxy routing)
        lb_url: 'my-app.{{ local_domain }}'

        # Base Docker image
        base_image: php:8.2-cli

        # System dependencies to install
        system_dependencies:
          - unzip
          - git
          - curl
          - zip

        # PHP extensions (Laravel-specific)
        php_extensions:
          - pdo
          - pdo_mysql
          - mbstring
          - xml
          - curl
          - zip

        # Monitoring configuration
        monitoring:
          prometheus:
            enabled: true
            port: 8000
            path: /metrics
          apm:
            enabled: true
            type: opentelemetry
            tempo_endpoint: http://tempo:4318
            protocol: http/protobuf
          logging:
            level: info
            format: json
            destination: stdout

        # Docker container configuration
        docker:
          name: my_laravel_app
          hostname: my_laravel_app
          exposed_port: 8000
          port_bindings:
            - "8000:8000"  # Host:Container port mapping
          volumes:
            # Mount your app directory
            - "../../apps/my_laravel_app:/var/www/html"
          working_dir: /var/www/html
          # Custom startup command (optional)
          command:
            - sh
            - -c
            - |
              if [ ! -f /usr/local/bin/composer ]; then
                curl -sS https://getcomposer.org/installer | php
                mv composer.phar /usr/local/bin/composer
                chmod +x /usr/local/bin/composer
              fi
              cd /var/www/html
              composer install --no-dev --no-interaction
              php artisan migrate --force || true
              php artisan serve --host=0.0.0.0 --port=8000

        # Application-specific configuration
        app_config:
          db_name: my_laravel_app
          db_user: my_laravel_app
          db_password: my_laravel_app_pass
          db_host: mysql
          db_port: 3306
          # Add any other environment variables your app needs
          APP_NAME: "My Laravel App"
          APP_ENV: production
          APP_DEBUG: "false"

Example: Adding a Django Application

plift:
  apps:
    django:
      my_django_app:
        lb_url: 'my-django.{{ local_domain }}'

        # Monitoring
        monitoring:
          prometheus:
            enabled: true
            port: 8000
            path: /metrics
          apm:
            enabled: true
            type: opentelemetry
            tempo_endpoint: http://tempo:4317
          logging:
            level: info
            format: json
            destination: stdout

        docker:
          name: my_django_app
          hostname: my_django_app
          exposed_port: 8000
          port_bindings:
            - "8001:8000"  # Use different host port
          volumes:
            - "../../apps/my_django_app:/app"
          env_vars:
            ALLOWED_HOSTS: "my-django.{{ local_domain }},localhost,127.0.0.1"
            PYTHONUNBUFFERED: "1"

        app_config:
          db_name: my_django_app
          db_user: my_django_app
          db_password: my_django_app_pass
          db_host: postgresql
          db_port: 5432
          SECRET_KEY: "your-secret-key-here"

Example: Adding a Node.js Application

plift:
  apps:
    nodejs:
      my_nodejs_app:
        lb_url: 'my-nodejs.{{ local_domain }}'

        monitoring:
          prometheus:
            enabled: true
            port: 3000
            path: /metrics
          apm:
            enabled: true
            type: opentelemetry
            tempo_endpoint: http://tempo:4317
          logging:
            level: info
            format: json
            destination: stdout

        docker:
          name: my_nodejs_app
          hostname: my_nodejs_app
          exposed_port: 3000
          port_bindings:
            - "3002:3000"
          volumes:
            - "../../apps/my_nodejs_app:/app"
            - "/app/node_modules"  # Anonymous volume for node_modules
          env_vars:
            NODE_ENV: production
            NODE_OPTIONS: "--require ./tracing.js"  # For OpenTelemetry

        app_config:
          db_name: my_nodejs_app
          db_user: my_nodejs_app
          db_password: my_nodejs_app_pass
          db_host: postgresql
          db_port: 5432

Example: Adding a Java/Spring Boot Application

plift:
  apps:
    java:
      my_java_app:
        lb_url: 'my-java.{{ local_domain }}'

        monitoring:
          prometheus:
            enabled: true
            port: 8080
            path: /actuator/prometheus
          apm:
            enabled: true
            type: opentelemetry
            tempo_endpoint: http://tempo:4317
          logging:
            level: info
            format: json
            destination: stdout

        docker:
          name: my_java_app
          hostname: my_java_app
          exposed_port: 8080
          port_bindings:
            - "8082:8080"
          # For Java apps, typically build JAR into image
          # volumes:
          #   - "../../apps/my_java_app:/app"
          command:
            - sh
            - -c
            - |
              if [ ! -f /tmp/opentelemetry-javaagent.jar ]; then
                curl -sSL -o /tmp/opentelemetry-javaagent.jar \
                  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.32.0/opentelemetry-javaagent.jar
              fi
              java -javaagent:/tmp/opentelemetry-javaagent.jar \
                   -jar /app/app.jar

        app_config:
          db_name: my_java_app
          db_user: my_java_app
          db_password: my_java_app_pass
          db_host: postgresql
          db_port: 5432
          SPRING_PROFILES_ACTIVE: production

Step 3: Using Git Repository (Optional)

If your app is in a Git repository, you can configure PLift to clone it automatically:

my_laravel_app:
  git_repo: https://github.com/yourusername/my-app.git
  git_branch: main  # Optional, defaults to master/main
  # ... rest of config ...

PLift will clone the repository to /apps/my_laravel_app during config generation.

Step 4: Generate Configurations

Generate the application-specific configurations:

# Generate app configs (Dockerfiles, .env files, etc.)
plift generate c=apps

# Generate HAProxy routing
plift generate c=default

# Generate database migrations
# (This will be done automatically, but you can regenerate)

Step 5: Set Up Database (If Needed)

If your app uses a database, PLift will automatically: - Create the database - Create the database user - Set up permissions

The migration will run automatically when you execute:

plift migrate-databases

Or you can manually configure database users in: - configs/databases/mysql/init.sls for MySQL - configs/databases/postgresql/init.sls for PostgreSQL

Step 6: Build and Start Your Application

# Build the application container
plift build-apps a=my_laravel_app

# Start the application
plift start-apps a=my_laravel_app

# Or start all apps
plift start-apps

Step 7: Verify Your Application

  1. Check container status:

    plift status
    

  2. View application logs:

    plift logs c=my_laravel_app
    

  3. Access your application:

  4. Via HAProxy: https://my-app.plift.local
  5. Direct port: http://localhost:8000 (if port binding is configured)

  6. Check monitoring:

  7. Prometheus: http://localhost:9090 (search for your app metrics)
  8. Grafana: http://localhost:3000 (check dashboards)

Configuration Reference

Required Fields

  • lb_url: URL for HAProxy routing (e.g., 'my-app.plift.local')
  • docker.name: Container name (must be unique)
  • docker.exposed_port: Port your app listens on inside container
  • docker.port_bindings: Host:Container port mapping
  • app_config: Application configuration (database, etc.)

Optional Fields

  • base_image: Docker base image (defaults per framework)
  • system_dependencies: System packages to install
  • php_extensions: PHP extensions (Laravel/Symfony)
  • python_packages: Python packages (Django)
  • npm_packages: NPM packages (Node.js)
  • maven_dependencies: Maven dependencies (Java)
  • monitoring: Monitoring configuration
  • docker.volumes: Volume mounts
  • docker.env_vars: Environment variables
  • docker.command: Custom startup command
  • git_repo: Git repository URL

Monitoring Configuration

All monitoring is optional but recommended:

monitoring:
  prometheus:
    enabled: true
    port: 8000
    path: /metrics
  apm:
    enabled: true
    type: opentelemetry
    tempo_endpoint: http://tempo:4318  # or :4317 for gRPC
    protocol: http/protobuf  # or grpc
  logging:
    level: info
    format: json
    destination: stdout

Common Scenarios

Scenario 1: App with Custom Dependencies

my_laravel_app:
  system_dependencies:
    - imagemagick
    - libpng-dev
  php_extensions:
    - gd
    - imagick
  # ... rest of config

Scenario 2: App with Multiple Databases

my_app:
  app_config:
    # Primary database
    db_name: my_app
    db_user: my_app
    db_password: my_app_pass
    db_host: postgresql

    # Secondary database (add as env vars)
    REDIS_HOST: redis
    REDIS_PORT: 6379
    CACHE_DRIVER: redis

Scenario 3: App with Custom Build Process

my_nodejs_app:
  docker:
    command:
      - sh
      - -c
      - |
        npm install
        npm run build
        npm start

Scenario 4: App with Health Checks

Add health check endpoint and configure in your app code. PLift will automatically discover it via Prometheus.

Troubleshooting

Application Won't Start

  1. Check logs:

    plift logs c=my_app
    

  2. Verify configuration:

    plift get-config VAL=apps OUT=yaml
    

  3. Check port conflicts:

    plift status
    # Ensure no other container uses the same host port
    

Database Connection Issues

  1. Ensure database is running:

    plift start-services s=mysql  # or postgresql
    

  2. Run migrations:

    plift migrate-databases
    

  3. Check database credentials in configs/apps/init.sls

HAProxy Not Routing

  1. Regenerate HAProxy config:

    plift generate c=default
    

  2. Restart HAProxy:

    plift restart-base
    

  3. Check lb_url matches domain:

  4. Should be: my-app.plift.local
  5. Not: my_app.plift.local (underscores not valid in DNS)

Monitoring Not Working

  1. Verify monitoring config in app config
  2. Check Prometheus targets: http://localhost:9090/targets
  3. Verify metrics endpoint is accessible from Prometheus
  4. Check OpenTelemetry endpoint if using APM

Best Practices

  1. Use Git repositories for version control
  2. Set unique port bindings to avoid conflicts
  3. Enable monitoring for all production-like apps
  4. Use environment variables for sensitive data
  5. Test locally before committing configs
  6. Document custom commands in your app's README
  7. Use health check endpoints for better monitoring

Next Steps

After adding your app:

  1. Generate traffic to test monitoring:

    plift generate-traffic requests=50
    

  2. Check Grafana dashboards for your app metrics

  3. Set up database users if you need custom permissions

  4. Configure additional services (Redis, RabbitMQ, etc.) if needed

Example: Complete Workflow

# 1. Add your app config to configs/apps/init.sls
# (Edit the file as shown above)

# 2. Generate all configurations
plift generate-all

# 3. Build your app container
plift build-apps a=my_app

# 4. Run database migrations
plift migrate-databases

# 5. Start your app
plift start-apps a=my_app

# 6. Verify it's running
plift status
plift logs c=my_app

# 7. Access your app
curl https://my-app.plift.local

# 8. Check monitoring
open http://localhost:3000  # Grafana
open http://localhost:9090  # Prometheus

Framework-Specific Notes

Laravel/Symfony (PHP)

  • Ensure composer.json exists in your app directory
  • PLift will auto-install Composer if not present
  • PHP extensions are installed automatically based on config
  • .env file is generated automatically

Django (Python)

  • Ensure requirements.txt exists
  • Database migrations run via Django's migration system
  • ALLOWED_HOSTS is automatically configured
  • Gunicorn is used as the WSGI server

Node.js

  • Ensure package.json exists
  • node_modules should be in anonymous volume to persist
  • OpenTelemetry requires tracing.js file (see examples)
  • Hot reload works with nodemon in development

Java/Spring Boot

  • Build JAR file before adding to PLift
  • OpenTelemetry Java agent is auto-downloaded
  • Actuator endpoints are pre-configured
  • application.properties is generated automatically

Getting Help

  • Check existing example apps in apps/example_*
  • Review generated configs in generated_configs/
  • Check Salt templates in salt/actions/generate/templates/
  • View logs: plift logs c=container_name