Skip to content

Deploying a Contao App

Introduction

Contao is a powerful, modern PHP-based content management system (CMS) that prioritizes flexibility and ease of use for both content creators and developers. Built with professional web agencies and enterprise requirements in mind, Contao provides a sophisticated platform for managing websites, digital assets, and content workflows.

What Makes Contao Special:

Flexible Data Container: Unlike traditional page-based CMSs, Contao uses a data container system that lets you create custom content types tailored to your specific needs. This flexibility means you’re not locked into predefined content structures.

Professional Asset Management: Built-in digital asset management with folder hierarchies, file versioning, and metadata handling makes managing media libraries straightforward for teams.

Intuitive Content Editing: The backend is designed to be approachable for content editors without technical knowledge, while remaining powerful enough for custom implementations.

Developer-Friendly: Built on Symfony components, Contao leverages modern PHP standards and practices. The architecture makes it easy to extend and customize for complex requirements.

Multi-Language Support: Native support for multiple languages and regional variations makes it ideal for global websites.

Enterprise Security: Role-based access control, audit logging, and granular permissions enable secure team collaboration.

Template Engine Integration: Contao uses Twig templates, giving developers a familiar, powerful tool for building website frontends.

Searchable and SEO-Ready: Built-in metadata management, URL aliases, and sitemap generation help your site rank well in search engines.

Contao lets you build anything from small business websites to complex enterprise portals. Unlike rigid templated systems, you define your own content types, workflows, and presentation layers—giving you complete control over your web presence.

This guide walks you through deploying Contao on Klutch.sh using Docker. You’ll learn how to set up the CMS with a database backend, configure proper file storage, implement security measures, optimize performance, and troubleshoot common deployment scenarios.

Prerequisites

Before deploying Contao to Klutch.sh, ensure you have:

  • A Klutch.sh account with dashboard access
  • A GitHub account for repository hosting
  • Docker installed locally for testing (optional but recommended)
  • Familiarity with PHP and web server concepts
  • A database (MySQL 8.0+ or PostgreSQL 10+) for Contao to use
  • Understanding of file permissions and server configuration
  • A domain name for your website (recommended for production)

Understanding Contao Architecture

Technology Stack

Contao is built on modern, battle-tested web technologies:

Backend Framework:

  • PHP 8.0+ for modern language features
  • Symfony components for routing, validation, and services
  • Doctrine ORM for database abstraction
  • Twig template engine for themes

Frontend:

  • Flexible templating system supporting any HTML/CSS framework
  • Built-in responsive image handling
  • Asset pipeline for CSS and JavaScript optimization

Database:

  • MySQL 8.0+ or compatible (MariaDB, Percona)
  • PostgreSQL 10+ as alternative
  • Doctrine migrations for version control of schema

Storage:

  • File system storage for media and assets
  • Optional CDN integration for asset delivery
  • Persistent volume support for uploaded files

Admin Interface:

  • Desktop-friendly backend UI
  • Real-time preview functionality
  • Built-in developer tools

Core Components

Content Management: Pages, articles, news, events, and custom content elements

Media Management: Digital asset library with folder hierarchies and permissions

User Management: Frontend and backend users with granular role-based permissions

Form Builder: Drag-and-drop form creation with validation and submission handling

Search Integration: Built-in search functionality with customizable indexing

Template System: Flexible Twig-based theming system

Admin Notifications: Audit logging and activity tracking

Installation and Setup

Step 1: Create Your Project Directory

Start with a dedicated directory for your Contao deployment:

Terminal window
mkdir contao-deployment
cd contao-deployment
git init

Step 2: Create Directory Structure

Set up the necessary directories for a production-ready deployment:

Terminal window
mkdir -p files config logs var/cache var/logs

Your project structure will look like:

contao-deployment/
├── Dockerfile
├── docker-entrypoint.sh
├── .env.example
├── .dockerignore
├── .gitignore
├── files/
│ └── (persistent media storage)
├── config/
│ └── (Contao configuration)
├── logs/
│ └── (application logs)
└── var/
├── cache/
└── logs/

Step 3: Create the Dockerfile

Create a Dockerfile in your project root for a production-ready Contao setup:

# Multi-stage build
FROM php:8.2-apache as builder
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
unzip \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libzip-dev \
libicu-dev \
&& rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \
docker-php-ext-install -j$(nproc) \
gd \
pdo_mysql \
pdo_pgsql \
zip \
intl \
opcache
# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /tmp
# Clone and build Contao
RUN git clone --depth 1 https://github.com/contao/contao.git . && \
composer install --no-interaction --optimize-autoloader --no-dev
# Runtime stage
FROM php:8.2-apache
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng6 \
libjpeg62-turbo \
libfreetype6 \
libzip4 \
libicu72 \
mysql-client \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-configure gd --with-freetype --with-jpeg && \
docker-php-ext-install -j$(nproc) \
gd \
pdo_mysql \
pdo_pgsql \
zip \
intl \
opcache
# Enable Apache modules
RUN a2enmod rewrite && \
a2enmod headers && \
a2enmod deflate
# Create application user
RUN useradd -m -u 1000 www-data-app
# Copy Apache configuration
COPY apache.conf /etc/apache2/sites-available/000-default.conf
# Copy application from builder
COPY --from=builder --chown=www-data-app:www-data-app /tmp /var/www/html
# Set working directory
WORKDIR /var/www/html
# Create directories with correct permissions
RUN mkdir -p files var/cache var/logs \
&& chown -R www-data-app:www-data-app files var \
&& chmod -R 755 files var
# Copy entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# Expose port
EXPOSE 80
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost/ || exit 1
# Set user
USER www-data-app
# Run entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["apache2-foreground"]

Step 4: Create Apache Configuration

Create apache.conf for proper Apache setup with Contao:

<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/html/public
# Logging
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Enable rewrite engine
<Directory /var/www/html/public>
Options FollowSymLinks
AllowOverride All
Require all granted
# Contao rewrite rules
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# Prevent access to hidden files
RewriteRule "^\." - [F]
# Route requests to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
</Directory>
# PHP configuration
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php-fpm.sock|fcgi://localhost"
</FilesMatch>
# Security headers
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
# Caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 week"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
</IfModule>
# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/xml
</IfModule>
</VirtualHost>

Step 5: Create Entrypoint Script

Create docker-entrypoint.sh for proper initialization:

#!/bin/bash
set -e
echo "Starting Contao initialization..."
# Load environment variables from .env if it exists
if [ -f /var/www/html/.env ]; then
export $(cat /var/www/html/.env | grep -v '#' | xargs)
fi
# Create necessary directories
mkdir -p var/cache var/logs
chown -R www-data-app:www-data-app var files
# Run database migrations if configured
if [ ! -z "$DATABASE_URL" ]; then
echo "Running database migrations..."
php bin/console doctrine:migrations:migrate --no-interaction
fi
# Clear caches
echo "Clearing application cache..."
php bin/console cache:clear --no-interaction
# Warmup caches
echo "Warming up caches..."
php bin/console cache:warmup --no-interaction
echo "Contao initialization complete. Starting Apache..."
# Execute the main command
exec "$@"

Make it executable:

Terminal window
chmod +x docker-entrypoint.sh

Step 6: Create Environment Configuration

Create .env.example as a reference:

5432/contao
# Database configuration
DATABASE_URL=mysql://root:password@localhost:3306/contao
# Or for PostgreSQL:
# Admin credentials (for initial setup)
CONTAO_ADMIN_USER=admin
CONTAO_ADMIN_PASSWORD=change-me-please
# Application environment
APP_ENV=production
APP_DEBUG=0
APP_SECRET=change-me-to-a-random-string
# SMTP configuration (optional)
MAILER_DSN=smtp://smtp.mailtrap.io:587?encryption=tls&username=YOUR_USERNAME&password=YOUR_PASSWORD
# Backup configuration (optional)
BACKUP_ENABLED=true
BACKUP_FOLDER=files/backup
# Encryption key (for secure data)
ENCRYPTION_KEY=change-me-to-a-random-string
# Upload limits
MAX_UPLOAD_SIZE=10M

Step 7: Create .dockerignore

Create .dockerignore to exclude unnecessary files:

.git
.gitignore
.github
.env.local
.env.production.local
*.log
.DS_Store
node_modules
vendor
.vscode
.idea
README.md
docs/
composer.lock
var/cache
var/logs
files/*
!files/.gitkeep

Step 8: Create .gitignore

Create .gitignore to prevent committing sensitive files:

# Environment
.env
.env.local
.env.*.local
# Cache and logs
var/cache/
var/logs/
*.log
logs/
# Media and uploads
files/
!files/.gitkeep
# Dependencies
vendor/
node_modules/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Contao specific
system/
config/database.yml

Step 9: Local Testing (Optional)

Test your Contao setup locally:

Terminal window
# Build the image
docker build -t contao-test .
# Run Contao locally with Docker
docker run -d \
--name contao-server \
-p 8080:80 \
-e DATABASE_URL="mysql://root:password@host.docker.internal:3306/contao" \
-e APP_ENV=dev \
-e APP_DEBUG=1 \
-v $(pwd)/files:/var/www/html/files \
-v $(pwd)/var:/var/www/html/var \
contao-test
# Wait for startup
sleep 10
# Access Contao
# http://localhost:8080
# View logs
docker logs -f contao-server
# Cleanup
docker stop contao-server
docker rm contao-server

Step 10: Commit to GitHub

Push your configuration to GitHub:

Terminal window
git add Dockerfile apache.conf docker-entrypoint.sh .env.example .dockerignore .gitignore
git commit -m "Add Contao CMS Docker configuration for Klutch.sh deployment"
git branch -M main
git remote add origin https://github.com/yourusername/contao-deployment.git
git push -u origin main

Deploying to Klutch.sh

Now let’s deploy your Contao CMS to Klutch.sh with proper database configuration and persistent storage.

Deployment Steps

  1. Access Klutch.sh Dashboard

    Navigate to klutch.sh/app and sign in with your GitHub account.

  2. Create a New Project

    In the Projects section, click “Create Project” and name it something like “Contao CMS” or “Website Platform”.

  3. Create a New App

    Within your project, click “Create App” to begin configuring your Contao deployment.

  4. Connect Your Repository
    • Select GitHub as your Git source
    • Choose your repository with the Contao Dockerfile
    • Select the branch to deploy (typically main)

    Klutch.sh will automatically detect the Dockerfile in your repository root.

  5. Configure Traffic Settings
    • Traffic Type: Select HTTP (Contao runs as a web application)
    • Internal Port: Set to 80 (Apache’s default listening port inside the container)
  6. Configure Environment Variables

    Add the following environment variables to configure your Contao instance:

    Database Configuration:

    Terminal window
    # MySQL database URL
    DATABASE_URL=mysql://contao_user:secure_password@your-db-host:3306/contao_db
    # Or PostgreSQL:
    # DATABASE_URL=postgresql://contao_user:secure_password@your-db-host:5432/contao_db

    Application Configuration:

    Terminal window
    # Environment (production recommended)
    APP_ENV=production
    # Debug mode (always false in production)
    APP_DEBUG=0
    # Application secret (generate a secure random string)
    APP_SECRET=your-secure-random-secret-string-here
    # Encryption key for secure data
    ENCRYPTION_KEY=your-secure-encryption-key

    Admin User Setup (for initial installation):

    Terminal window
    # Admin username and password (change after first login)
    CONTAO_ADMIN_USER=admin
    CONTAO_ADMIN_PASSWORD=strong-initial-password

    Email Configuration:

    Terminal window
    # SMTP configuration for sending emails
    MAILER_DSN=smtp://smtp.example.com:587?encryption=tls&username=your-email@example.com&password=your-password
    # From address for automated emails
    MAILER_FROM_NAME="Your Site Name"
    MAILER_FROM_ADDRESS=noreply@example.com

    Performance and Uploads:

    Terminal window
    # Maximum upload file size
    MAX_UPLOAD_SIZE=10M
    # Image processing quality
    IMAGE_QUALITY=85
    # Enable backup functionality
    BACKUP_ENABLED=true

    Recommended Settings:

    Terminal window
    # Cache busting for assets
    ASSET_CACHE_BUST=true
    # Enable security headers
    SECURITY_HEADERS_ENABLED=true

    Security Note:

    • Generate strong, unique values for all secrets using openssl rand -base64 32
    • Never commit .env file to Git
    • Store sensitive values in Klutch.sh environment variables, not in code
    • Change admin credentials immediately after first login
    • Use strong database passwords with special characters
  7. Configure Persistent Storage

    Contao needs persistent storage for uploaded media and cache:

    Volume 1 - Media Files:

    • Mount Path: /var/www/html/files
    • Size: 10-50 GB (depends on media library size)

    Volume 2 - Cache and Logs:

    • Mount Path: /var/www/html/var
    • Size: 5-10 GB

    Guidelines for volume sizes:

    • Small site (< 1000 pages, < 100 media files): 10 GB for files, 5 GB for var
    • Medium site (1000-10000 pages, < 1000 media files): 25 GB for files, 7 GB for var
    • Large site (10000+ pages, large media library): 50+ GB for files, 10+ GB for var

    Important: Without persistent storage, all uploaded files and caches will be lost on container restart. This is critical for production deployments.

  8. Configure Compute Resources

    Choose appropriate resources based on expected traffic and content:

    Small Deployment (< 50,000 visitors/month):

    • CPU: 1 core
    • RAM: 1 GB
    • Suitable for: Small business sites, portfolios

    Medium Deployment (50,000-500,000 visitors/month):

    • CPU: 2 cores
    • RAM: 2 GB
    • Suitable for: Growing businesses, community sites

    Large Deployment (500,000-2,000,000 visitors/month):

    • CPU: 4 cores
    • RAM: 4 GB
    • Suitable for: Regional businesses, high-traffic sites

    Enterprise (2,000,000+ visitors/month):

    • CPU: 8+ cores
    • RAM: 8+ GB
    • Suitable for: Enterprise portals, high-traffic platforms

    You can scale up or down based on actual performance metrics.

  9. Deploy the Application

    Click “Create” to start the deployment. Klutch.sh will:

    1. Clone your repository
    2. Build the Docker image
    3. Configure environment variables
    4. Set up persistent storage volumes
    5. Start the Contao container
    6. Assign a public URL (e.g., example-app.klutch.sh)
    7. Configure automatic HTTPS with SSL certificates

    Deployment typically takes 5-10 minutes.

  10. Monitor Deployment Progress

    Track the deployment:

    • Go to the Deployments tab
    • View real-time build logs
    • Wait for status to show “Running”
    • Check that all environment variables are set correctly
  11. Complete Initial Setup**

    After deployment, complete the Contao setup:

    1. Navigate to your deployed URL: https://example-app.klutch.sh
    2. You should see the Contao installation wizard
    3. Verify database connection
    4. Create your first user account
    5. Configure site information
    6. Set up your first page
    7. Test backend login at /contao/login

    If you receive a database error, verify your DATABASE_URL environment variable is correct and the database is accessible from Klutch.sh.

  12. Configure Your Domain

    Add your custom domain to Klutch.sh:

    1. In Klutch.sh dashboard, go to Domains
    2. Click “Add Custom Domain”
    3. Enter your domain (e.g., www.example.com)
    4. Update DNS with CNAME record pointing to example-app.klutch.sh
    5. Wait for DNS propagation and SSL certificate provisioning

    Update Contao Configuration:

    1. Go to Contao backend admin panel
    2. Navigate to System → Settings
    3. Update site configuration to use your custom domain
    4. Save changes
  13. Verify Installation

    After deployment, verify everything is working:

    1. Frontend Access:

      Terminal window
      curl https://example-app.klutch.sh

      Should return HTML content of your homepage.

    2. Backend Login:

      • Navigate to https://example-app.klutch.sh/contao/login
      • Log in with your admin credentials
      • Verify you can access the backend
    3. Database Connection:

      • In Contao backend, go to System → Database
      • Verify tables are created correctly
      • Check for any database errors
    4. File Uploads:

      • Upload a test image in the Media Manager
      • Verify file appears in the files directory
      • Test that image displays correctly
    5. Check Application Logs:

      • View logs in Klutch.sh dashboard
      • Look for any error messages
      • Verify database migrations completed successfully

Database Configuration

Contao requires a database to store pages, content, users, and configuration. Choose between MySQL and PostgreSQL based on your hosting provider and preferences.

MySQL Configuration

MySQL 8.0+ is the recommended database for most Contao deployments.

Provider Recommendations:

Setup:

Terminal window
# Create database and user
mysql -u root -p
CREATE DATABASE contao_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'contao_user'@'%' IDENTIFIED BY 'secure-password-here';
GRANT ALL PRIVILEGES ON contao_db.* TO 'contao_user'@'%';
FLUSH PRIVILEGES;

Configuration:

Terminal window
DATABASE_URL=mysql://contao_user:secure-password@your-db-host:3306/contao_db?serverVersion=8.0

PostgreSQL Configuration

PostgreSQL is excellent for high-traffic sites with complex queries.

Provider Recommendations:

Setup:

-- Connect to PostgreSQL
psql -U postgres
-- Create database
CREATE DATABASE contao_db ENCODING 'UTF8';
-- Create user
CREATE USER contao_user WITH PASSWORD 'secure-password-here';
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE contao_db TO contao_user;
GRANT ALL PRIVILEGES ON SCHEMA public TO contao_user;

Configuration:

Terminal window
DATABASE_URL=postgresql://contao_user:secure-password@your-db-host:5432/contao_db?sslmode=require

Database Migrations

Contao automatically creates tables on first run. After upgrading, run migrations:

Terminal window
php bin/console doctrine:migrations:migrate

This happens automatically in the Docker entrypoint script.

Getting Started with Contao

Accessing the Backend

The Contao backend is where you manage your website:

  1. Navigate to https://your-site.klutch.sh/contao/login
  2. Log in with your admin credentials
  3. You’ll see the main dashboard

Creating Pages

Pages are the core structure of your website:

  1. Go to Pages in the left sidebar
  2. Click New Page
  3. Enter page title and URL alias
  4. Configure page type (Regular page, Error page, etc.)
  5. Set visibility and access permissions
  6. Publish the page

Adding Content

Add various content types to pages:

Text Elements:

  • Headings, paragraphs, lists
  • HTML blocks for custom content
  • Code snippets for embeds

Media Elements:

  • Images with gallery options
  • Videos and embeds
  • Audio players

Forms:

  • Form builder with validation
  • Custom form fields
  • Email notification handling

Managing Media

The Media Manager is your digital asset library:

  1. Go to Media Manager
  2. Create folders to organize files
  3. Upload images, documents, videos
  4. View file metadata and edit
  5. Use in pages via insert buttons

User Management

Manage backend and frontend users:

Backend Users (content editors):

  • Go to System → Users
  • Create users with specific permissions
  • Assign to groups for role management

Frontend Users (website visitors):

  • Go to Frontend → Members
  • Create login accounts for gated content
  • Manage member groups and permissions

Publishing Content

Contao has a flexible publication workflow:

  1. Create and edit content
  2. Click Save to save draft
  3. Set publication date if needed
  4. Click Publish to go live
  5. Schedule unpublication if desired

Security Best Practices

User Access Control

Strong Passwords:

  • Enforce minimum 12 characters
  • Require mixed case, numbers, special characters
  • Change default admin password immediately

Role-Based Permissions:

  • Limit backend access to necessary users only
  • Assign users to specific groups
  • Grant granular permissions per group
  • Regularly audit user access

Database Security

Connection Security:

  • Always use database password in environment variables
  • Enable SSL/TLS for database connections
  • Use secure connection strings

Backup Strategy:

Terminal window
# Automated backups of database
DATABASE_BACKUP_ENABLED=true
DATABASE_BACKUP_RETENTION_DAYS=30

Encryption:

  • Generate strong encryption keys
  • Rotate encryption keys periodically
  • Store keys in environment variables, never in code

File Upload Security

Restrict File Types:

  • Only allow necessary file types (images, documents)
  • Block executable files
  • Validate file contents, not just extensions

Upload Limits:

Terminal window
# Set reasonable upload limits
MAX_UPLOAD_SIZE=10M
MAX_FILE_SIZE=100M

Virus Scanning (optional):

  • Consider integrating ClamAV for malware detection
  • Scan uploads before storing

HTTPS and SSL

All Klutch.sh deployments automatically use HTTPS:

  • Valid SSL certificates provided automatically
  • All traffic encrypted in transit
  • Set security headers:
Terminal window
SECURITY_HEADERS_ENABLED=true
X_CONTENT_TYPE_OPTIONS=nosniff
X_FRAME_OPTIONS=SAMEORIGIN
X_XSS_PROTECTION=1

Regular Updates

Keep Contao and dependencies updated:

  1. Monitor Contao security advisories
  2. Update Composer dependencies regularly
  3. Test updates in staging before production
  4. Keep PHP version current
  5. Update OS packages

Content Security

Prevent Common Attacks:

  • SQL injection protection (automatic with ORM)
  • Cross-site scripting (automatic HTML escaping)
  • Cross-site request forgery (CSRF tokens)
  • Brute force protection on login

Audit Logging:

  • Enable activity logging
  • Monitor suspicious access
  • Review user actions regularly

Performance Optimization

Caching

Contao includes multiple caching layers:

Page Caching:

Terminal window
# Enable page caching
CACHE_PAGES=true
CACHE_TTL=3600

Query Caching:

  • Doctrine query cache automatically enabled
  • Reduces database queries
  • Improves response times

Asset Caching:

Terminal window
# Cache CSS and JavaScript
ASSET_CACHE_BUST=true

Image Optimization

Contao automatically optimizes images:

JPEG Compression:

Terminal window
IMAGE_QUALITY=85

Responsive Images:

  • Automatic srcset generation
  • WebP format support
  • Lazy loading integration

CDN Integration:

Point your CDN to the files directory for fast asset delivery:

CDN_URL=https://cdn.example.com/files

Database Optimization

Query Performance:

  • Contao automatically indexes important columns
  • Use database tools to identify slow queries
  • Consider caching queries for heavy operations

Connection Pooling:

Terminal window
# Database connection settings
DATABASE_POOL_SIZE=20

Nginx/Apache Tuning

The provided Apache configuration includes:

  • Gzip compression for text assets
  • Expires headers for browser caching
  • Security headers for protection
  • Rewrite rules for clean URLs

Monitor response times and adjust as needed.

Troubleshooting

Issue 1: Blank Page on Installation

Symptoms: White blank page when accessing the site

Solutions:

  1. Check Database Connection:

    • Verify DATABASE_URL environment variable
    • Test connection from container to database
    • Check database user permissions
  2. Check PHP Errors:

    • View application logs in Klutch.sh dashboard
    • Look for PHP fatal errors
    • Check database connectivity
  3. Clear Cache:

    • Delete var/cache directory
    • Run: php bin/console cache:clear
    • Restart container
  4. Verify File Permissions:

    • Check files and var directories exist
    • Ensure correct ownership (www-data-app)
    • Verify readable and writable

Issue 2: Database Connection Error

Symptoms: “Cannot connect to database” error

Solutions:

  1. Verify Connection String:

    • Check DATABASE_URL format
    • Verify hostname, username, password
    • Ensure database name matches
  2. Network Connectivity:

    • Test database host is reachable
    • Check firewall rules allow connection
    • Verify database is running
  3. Database Exists:

    • Confirm database created successfully
    • Check user has necessary permissions
    • Run migrations: php bin/console doctrine:migrations:migrate
  4. Credentials:

    • Verify special characters in password are URL-encoded
    • Use @ symbol correctly in URL
    • Test credentials manually if possible

Issue 3: Cannot Upload Files

Symptoms: Upload fails or files not appearing

Solutions:

  1. Check Persistent Storage:

    • Verify persistent volume attached to /var/www/html/files
    • Check volume has sufficient free space
    • Ensure correct mount path
  2. File Permissions:

    • Verify files directory is writable
    • Check ownership is www-data-app:www-data-app
    • Review filesystem permissions
  3. Upload Limits:

    • Check MAX_UPLOAD_SIZE environment variable
    • Verify file size is under limit
    • Review PHP upload limits in Apache
  4. Disk Space:

    • Monitor available space in persistent volume
    • Implement cleanup of old files
    • Archive old uploads if needed

Issue 4: Backend Login Issues

Symptoms: Cannot log in to admin panel, “Invalid credentials”

Solutions:

  1. Verify Admin User Created:

    • Check database for admin users
    • Verify user account is active
    • Ensure password is set correctly
  2. Clear Sessions:

    • Delete var/sessions if it exists
    • Clear browser cookies
    • Try incognito/private browsing
  3. Check Admin URL:

    • Verify access path: /contao/login
    • Use custom domain if configured
    • Check HTTPS is being used
  4. Database Issues:

    • Verify user table exists
    • Check user account active flag
    • Review error logs for details

Issue 5: Slow Page Load Times

Symptoms: Slow response times, timeouts

Solutions:

  1. Enable Caching:

    • Verify cache is enabled
    • Check cache directory writable
    • Monitor cache hit rates
  2. Database Performance:

    • Check for slow queries in logs
    • Add database indexes if needed
    • Consider query caching
  3. Resource Constraints:

    • Monitor CPU and memory usage
    • Check if container has enough resources
    • Consider upgrading resources
  4. Debug Mode:

    • Ensure APP_DEBUG=0 in production
    • Debug slows down performance
    • Only enable for development

Issue 6: Assets Not Loading (CSS, JavaScript)

Symptoms: Page loads but looks broken, missing styling

Solutions:

  1. Check Asset Generation:

    • Verify asset:install command ran
    • Check public/files directory exists
    • Ensure assets compiled correctly
  2. File Permissions:

    • Check public directory readable
    • Verify asset files present
    • Review Apache file access rules
  3. Cache Issues:

    • Clear browser cache

    • Set cache busting:

      Terminal window
      ASSET_CACHE_BUST=true
    • Restart container

  4. CDN Configuration:

    • If using CDN, verify files are synced
    • Check CDN_URL is correct
    • Test CDN origin is reachable

Issue 7: Email Not Sending

Symptoms: Scheduled emails not sent, email queue stuck

Solutions:

  1. Verify Configuration:

    • Check MAILER_DSN is set correctly
    • Test SMTP credentials
    • Verify mail provider settings
  2. Check Email Logs:

    • View application logs for mail errors
    • Monitor email queue status
    • Check for authentication failures
  3. Run Mail Queue:

    Terminal window
    php bin/console messenger:consume async
  4. Sender Verification:

    • Check MAILER_FROM_ADDRESS is valid
    • Verify domain DNS records (SPF, DKIM)
    • Test with known email

Issue 8: Memory Limit Errors

Symptoms: “Allowed memory size exceeded” errors

Solutions:

  1. Increase Memory Limit:

    Terminal window
    # Set higher PHP memory limit
    MEMORY_LIMIT=512M
  2. Upgrade Resources:

    • Increase container RAM in Klutch.sh
    • Monitor actual memory usage
    • Profile code for memory leaks
  3. Optimize Queries:

    • Check for large result sets
    • Implement pagination
    • Use query limits

Issue 9: Media Manager Errors

Symptoms: Error accessing Media Manager, file operations fail

Solutions:

  1. Check Permissions:

    • Verify user has media permissions
    • Check file/folder ownership
    • Ensure execute permissions on directories
  2. Disk Space:

    • Verify persistent volume has space
    • Monitor media directory size
    • Archive or delete old files if needed
  3. Filesystem Issues:

    • Check for filesystem errors
    • Verify disk is not corrupted
    • Restart container to remount volume

Issue 10: Deployment Failures

Symptoms: Deployment doesn’t complete, “Build failed” errors

Solutions:

  1. Check Build Logs:

    • Review Klutch.sh deployment logs
    • Look for specific error messages
    • Check Dockerfile syntax
  2. Database Migrations:

    • If migrations fail, deployment fails
    • Verify database is accessible
    • Test migrations locally first
  3. Dependencies:

    • Ensure all Composer dependencies install
    • Check for private repositories
    • Verify dependency versions
  4. File Size:

    • Check repository isn’t too large
    • Verify Dockerfile is reasonable size
    • Consider excluding large files with .dockerignore

Custom Domains

Using a custom domain makes your site professional and helps with SEO.

Step 1: Add Domain in Klutch.sh

  1. Go to your Contao app in Klutch.sh dashboard
  2. Navigate to Domains
  3. Click “Add Custom Domain”
  4. Enter your domain (e.g., www.example.com)
  5. Save

Step 2: Configure DNS

Update your domain provider DNS records:

Type: CNAME
Name: www
Value: example-app.klutch.sh
TTL: 3600

For root domain (@):

Type: CNAME (if supported by provider)
Value: example-app.klutch.sh

If your provider doesn’t support root CNAME, use A record pointing to Klutch.sh IP.

Step 3: Configure Contao

Update Contao to use your domain:

  1. Log in to Contao backend
  2. Go to System → Settings → Site Configuration
  3. Set the site domain to your custom domain
  4. Save changes
  5. Clear cache

Step 4: Verify Setup

  1. Wait for DNS propagation (up to 1 hour)

  2. Test domain resolution:

    Terminal window
    nslookup www.example.com
  3. Verify HTTPS certificate is active

  4. Test site loads correctly on custom domain

Production Best Practices

Backup Strategy

What to Backup:

  1. Database (complete database dump)
  2. Files directory (all uploads and media)
  3. Configuration and custom code

Backup Schedule:

  • Hourly: Database incremental backup
  • Daily: Full database and files backup
  • Weekly: Archival backup to cold storage
  • Monthly: Long-term retention backup

Backup Commands:

Terminal window
# MySQL backup
mysqldump -u contao_user -p contao_db | gzip > /backups/contao-$(date +%Y%m%d).sql.gz
# PostgreSQL backup
pg_dump postgresql://contao_user:password@host/contao_db | gzip > /backups/contao-$(date +%Y%m%d).sql.gz
# Files backup
tar -czf /backups/contao-files-$(date +%Y%m%d).tar.gz /var/www/html/files

Restore Procedures:

  • Document restoration steps
  • Test recovery monthly
  • Verify data integrity after restore
  • Keep offline backup copies

Monitoring

Key Metrics to Monitor:

  • CPU usage (alert if > 80% sustained)
  • Memory usage (alert if > 90%)
  • Disk space (alert if < 10% free)
  • Response times (alert if > 2 seconds)
  • Error rates in logs
  • Database query performance

Alerts:

  • Set up monitoring via Klutch.sh
  • Get notifications for critical issues
  • Monitor during traffic spikes
  • Review logs regularly

Security Maintenance

Regular Tasks:

Daily:

  • Monitor error logs
  • Check for unauthorized access attempts
  • Review failed login attempts

Weekly:

  • Security updates check
  • Database integrity check
  • Backup verification

Monthly:

  • Full security audit
  • Access control review
  • Password strength verification
  • Update dependencies

Quarterly:

  • Major updates testing
  • Security assessment
  • Performance review
  • Capacity planning

Scaling Strategies

When to Scale:

  • CPU consistently > 70%
  • Memory regularly > 80%
  • Response times increasing
  • Database getting slow

Vertical Scaling (recommended first):

  • Increase CPU cores
  • Increase RAM
  • Upgrade storage to faster disk
  • Improve database indexes

Horizontal Scaling (for very large sites):

  • Multiple Contao instances with load balancer
  • Shared database backend
  • Shared file storage
  • Cache layer (Redis)

Additional Resources

Conclusion

You now have a production-ready Contao deployment running on Klutch.sh. You’ve learned how to build a multi-stage Docker image that separates build and runtime dependencies, configure Apache with proper rewrite rules and security headers, set up either MySQL or PostgreSQL for data storage, implement persistent storage for media files and cache, and apply security best practices for protecting your CMS.

Contao’s flexibility lets you build anything from simple brochure sites to complex web applications. The data container system means you’re never limited by predefined content types—define your own content structures as your needs evolve.

Klutch.sh handles the infrastructure complexity, so you can focus on what matters: creating great content and building features. Automatic HTTPS, scalable resources, and persistent storage mean your site is production-ready out of the box.

Monitor your deployment’s performance, keep backups current, and update regularly. With proper maintenance, your Contao site will serve your audience reliably for years to come.

For questions, check out the Contao documentation, community forums, or Klutch.sh support. Happy building!