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:
mkdir contao-deploymentcd contao-deploymentgit initStep 2: Create Directory Structure
Set up the necessary directories for a production-ready deployment:
mkdir -p files config logs var/cache var/logsYour 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 buildFROM php:8.2-apache as builder
# Install system dependenciesRUN 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 extensionsRUN docker-php-ext-configure gd --with-freetype --with-jpeg && \ docker-php-ext-install -j$(nproc) \ gd \ pdo_mysql \ pdo_pgsql \ zip \ intl \ opcache
# Install ComposerCOPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /tmp
# Clone and build ContaoRUN git clone --depth 1 https://github.com/contao/contao.git . && \ composer install --no-interaction --optimize-autoloader --no-dev
# Runtime stageFROM php:8.2-apache
# Install runtime dependenciesRUN 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 extensionsRUN 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 modulesRUN a2enmod rewrite && \ a2enmod headers && \ a2enmod deflate
# Create application userRUN useradd -m -u 1000 www-data-app
# Copy Apache configurationCOPY apache.conf /etc/apache2/sites-available/000-default.conf
# Copy application from builderCOPY --from=builder --chown=www-data-app:www-data-app /tmp /var/www/html
# Set working directoryWORKDIR /var/www/html
# Create directories with correct permissionsRUN mkdir -p files var/cache var/logs \ && chown -R www-data-app:www-data-app files var \ && chmod -R 755 files var
# Copy entrypoint scriptCOPY docker-entrypoint.sh /usr/local/bin/entrypoint.shRUN chmod +x /usr/local/bin/entrypoint.sh
# Expose portEXPOSE 80
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost/ || exit 1
# Set userUSER www-data-app
# Run entrypointENTRYPOINT ["/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/bashset -e
echo "Starting Contao initialization..."
# Load environment variables from .env if it existsif [ -f /var/www/html/.env ]; then export $(cat /var/www/html/.env | grep -v '#' | xargs)fi
# Create necessary directoriesmkdir -p var/cache var/logschown -R www-data-app:www-data-app var files
# Run database migrations if configuredif [ ! -z "$DATABASE_URL" ]; then echo "Running database migrations..." php bin/console doctrine:migrations:migrate --no-interactionfi
# Clear cachesecho "Clearing application cache..."php bin/console cache:clear --no-interaction
# Warmup cachesecho "Warming up caches..."php bin/console cache:warmup --no-interaction
echo "Contao initialization complete. Starting Apache..."
# Execute the main commandexec "$@"Make it executable:
chmod +x docker-entrypoint.shStep 6: Create Environment Configuration
Create .env.example as a reference:
# Database configurationDATABASE_URL=mysql://root:password@localhost:3306/contao# Or for PostgreSQL:# Admin credentials (for initial setup)CONTAO_ADMIN_USER=adminCONTAO_ADMIN_PASSWORD=change-me-please
# Application environmentAPP_ENV=productionAPP_DEBUG=0APP_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=trueBACKUP_FOLDER=files/backup
# Encryption key (for secure data)ENCRYPTION_KEY=change-me-to-a-random-string
# Upload limitsMAX_UPLOAD_SIZE=10MStep 7: Create .dockerignore
Create .dockerignore to exclude unnecessary files:
.git.gitignore.github.env.local.env.production.local*.log.DS_Storenode_modulesvendor.vscode.ideaREADME.mddocs/composer.lockvar/cachevar/logsfiles/*!files/.gitkeepStep 8: Create .gitignore
Create .gitignore to prevent committing sensitive files:
# Environment.env.env.local.env.*.local
# Cache and logsvar/cache/var/logs/*.loglogs/
# Media and uploadsfiles/!files/.gitkeep
# Dependenciesvendor/node_modules/
# IDE.vscode/.idea/*.swp*.swo
# OS.DS_StoreThumbs.db
# Contao specificsystem/config/database.ymlStep 9: Local Testing (Optional)
Test your Contao setup locally:
# Build the imagedocker build -t contao-test .
# Run Contao locally with Dockerdocker 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 startupsleep 10
# Access Contao# http://localhost:8080
# View logsdocker logs -f contao-server
# Cleanupdocker stop contao-serverdocker rm contao-serverStep 10: Commit to GitHub
Push your configuration to GitHub:
git add Dockerfile apache.conf docker-entrypoint.sh .env.example .dockerignore .gitignoregit commit -m "Add Contao CMS Docker configuration for Klutch.sh deployment"git branch -M maingit remote add origin https://github.com/yourusername/contao-deployment.gitgit push -u origin mainDeploying to Klutch.sh
Now let’s deploy your Contao CMS to Klutch.sh with proper database configuration and persistent storage.
Deployment Steps
-
Access Klutch.sh Dashboard
Navigate to klutch.sh/app and sign in with your GitHub account.
-
Create a New Project
In the Projects section, click “Create Project” and name it something like “Contao CMS” or “Website Platform”.
-
Create a New App
Within your project, click “Create App” to begin configuring your Contao deployment.
-
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.
-
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)
-
Configure Environment Variables
Add the following environment variables to configure your Contao instance:
Database Configuration:
Terminal window # MySQL database URLDATABASE_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_dbApplication 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 dataENCRYPTION_KEY=your-secure-encryption-keyAdmin User Setup (for initial installation):
Terminal window # Admin username and password (change after first login)CONTAO_ADMIN_USER=adminCONTAO_ADMIN_PASSWORD=strong-initial-passwordEmail Configuration:
Terminal window # SMTP configuration for sending emailsMAILER_DSN=smtp://smtp.example.com:587?encryption=tls&username=your-email@example.com&password=your-password# From address for automated emailsMAILER_FROM_NAME="Your Site Name"MAILER_FROM_ADDRESS=noreply@example.comPerformance and Uploads:
Terminal window # Maximum upload file sizeMAX_UPLOAD_SIZE=10M# Image processing qualityIMAGE_QUALITY=85# Enable backup functionalityBACKUP_ENABLED=trueRecommended Settings:
Terminal window # Cache busting for assetsASSET_CACHE_BUST=true# Enable security headersSECURITY_HEADERS_ENABLED=trueSecurity Note:
- Generate strong, unique values for all secrets using
openssl rand -base64 32 - Never commit
.envfile 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
- Generate strong, unique values for all secrets using
-
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.
- Mount Path:
-
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.
-
Deploy the Application
Click “Create” to start the deployment. Klutch.sh will:
- Clone your repository
- Build the Docker image
- Configure environment variables
- Set up persistent storage volumes
- Start the Contao container
- Assign a public URL (e.g.,
example-app.klutch.sh) - Configure automatic HTTPS with SSL certificates
Deployment typically takes 5-10 minutes.
-
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
-
Complete Initial Setup**
After deployment, complete the Contao setup:
- Navigate to your deployed URL:
https://example-app.klutch.sh - You should see the Contao installation wizard
- Verify database connection
- Create your first user account
- Configure site information
- Set up your first page
- Test backend login at
/contao/login
If you receive a database error, verify your
DATABASE_URLenvironment variable is correct and the database is accessible from Klutch.sh. - Navigate to your deployed URL:
-
Configure Your Domain
Add your custom domain to Klutch.sh:
- In Klutch.sh dashboard, go to Domains
- Click “Add Custom Domain”
- Enter your domain (e.g.,
www.example.com) - Update DNS with CNAME record pointing to
example-app.klutch.sh - Wait for DNS propagation and SSL certificate provisioning
Update Contao Configuration:
- Go to Contao backend admin panel
- Navigate to System → Settings
- Update site configuration to use your custom domain
- Save changes
-
Verify Installation
After deployment, verify everything is working:
-
Frontend Access:
Terminal window curl https://example-app.klutch.shShould return HTML content of your homepage.
-
Backend Login:
- Navigate to
https://example-app.klutch.sh/contao/login - Log in with your admin credentials
- Verify you can access the backend
- Navigate to
-
Database Connection:
- In Contao backend, go to System → Database
- Verify tables are created correctly
- Check for any database errors
-
File Uploads:
- Upload a test image in the Media Manager
- Verify file appears in the files directory
- Test that image displays correctly
-
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:
# Create database and usermysql -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:
DATABASE_URL=mysql://contao_user:secure-password@your-db-host:3306/contao_db?serverVersion=8.0PostgreSQL Configuration
PostgreSQL is excellent for high-traffic sites with complex queries.
Provider Recommendations:
Setup:
-- Connect to PostgreSQLpsql -U postgres
-- Create databaseCREATE DATABASE contao_db ENCODING 'UTF8';
-- Create userCREATE USER contao_user WITH PASSWORD 'secure-password-here';
-- Grant privilegesGRANT ALL PRIVILEGES ON DATABASE contao_db TO contao_user;GRANT ALL PRIVILEGES ON SCHEMA public TO contao_user;Configuration:
DATABASE_URL=postgresql://contao_user:secure-password@your-db-host:5432/contao_db?sslmode=requireDatabase Migrations
Contao automatically creates tables on first run. After upgrading, run migrations:
php bin/console doctrine:migrations:migrateThis happens automatically in the Docker entrypoint script.
Getting Started with Contao
Accessing the Backend
The Contao backend is where you manage your website:
- Navigate to
https://your-site.klutch.sh/contao/login - Log in with your admin credentials
- You’ll see the main dashboard
Creating Pages
Pages are the core structure of your website:
- Go to Pages in the left sidebar
- Click New Page
- Enter page title and URL alias
- Configure page type (Regular page, Error page, etc.)
- Set visibility and access permissions
- 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:
- Go to Media Manager
- Create folders to organize files
- Upload images, documents, videos
- View file metadata and edit
- 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:
- Create and edit content
- Click Save to save draft
- Set publication date if needed
- Click Publish to go live
- 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:
# Automated backups of databaseDATABASE_BACKUP_ENABLED=trueDATABASE_BACKUP_RETENTION_DAYS=30Encryption:
- 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:
# Set reasonable upload limitsMAX_UPLOAD_SIZE=10MMAX_FILE_SIZE=100MVirus 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:
SECURITY_HEADERS_ENABLED=trueX_CONTENT_TYPE_OPTIONS=nosniffX_FRAME_OPTIONS=SAMEORIGINX_XSS_PROTECTION=1Regular Updates
Keep Contao and dependencies updated:
- Monitor Contao security advisories
- Update Composer dependencies regularly
- Test updates in staging before production
- Keep PHP version current
- 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:
# Enable page cachingCACHE_PAGES=trueCACHE_TTL=3600Query Caching:
- Doctrine query cache automatically enabled
- Reduces database queries
- Improves response times
Asset Caching:
# Cache CSS and JavaScriptASSET_CACHE_BUST=trueImage Optimization
Contao automatically optimizes images:
JPEG Compression:
IMAGE_QUALITY=85Responsive 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/filesDatabase Optimization
Query Performance:
- Contao automatically indexes important columns
- Use database tools to identify slow queries
- Consider caching queries for heavy operations
Connection Pooling:
# Database connection settingsDATABASE_POOL_SIZE=20Nginx/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:
-
Check Database Connection:
- Verify
DATABASE_URLenvironment variable - Test connection from container to database
- Check database user permissions
- Verify
-
Check PHP Errors:
- View application logs in Klutch.sh dashboard
- Look for PHP fatal errors
- Check database connectivity
-
Clear Cache:
- Delete
var/cachedirectory - Run:
php bin/console cache:clear - Restart container
- Delete
-
Verify File Permissions:
- Check
filesandvardirectories exist - Ensure correct ownership (www-data-app)
- Verify readable and writable
- Check
Issue 2: Database Connection Error
Symptoms: “Cannot connect to database” error
Solutions:
-
Verify Connection String:
- Check
DATABASE_URLformat - Verify hostname, username, password
- Ensure database name matches
- Check
-
Network Connectivity:
- Test database host is reachable
- Check firewall rules allow connection
- Verify database is running
-
Database Exists:
- Confirm database created successfully
- Check user has necessary permissions
- Run migrations:
php bin/console doctrine:migrations:migrate
-
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:
-
Check Persistent Storage:
- Verify persistent volume attached to
/var/www/html/files - Check volume has sufficient free space
- Ensure correct mount path
- Verify persistent volume attached to
-
File Permissions:
- Verify
filesdirectory is writable - Check ownership is www-data-app:www-data-app
- Review filesystem permissions
- Verify
-
Upload Limits:
- Check
MAX_UPLOAD_SIZEenvironment variable - Verify file size is under limit
- Review PHP upload limits in Apache
- Check
-
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:
-
Verify Admin User Created:
- Check database for admin users
- Verify user account is active
- Ensure password is set correctly
-
Clear Sessions:
- Delete
var/sessionsif it exists - Clear browser cookies
- Try incognito/private browsing
- Delete
-
Check Admin URL:
- Verify access path:
/contao/login - Use custom domain if configured
- Check HTTPS is being used
- Verify access path:
-
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:
-
Enable Caching:
- Verify cache is enabled
- Check cache directory writable
- Monitor cache hit rates
-
Database Performance:
- Check for slow queries in logs
- Add database indexes if needed
- Consider query caching
-
Resource Constraints:
- Monitor CPU and memory usage
- Check if container has enough resources
- Consider upgrading resources
-
Debug Mode:
- Ensure
APP_DEBUG=0in production - Debug slows down performance
- Only enable for development
- Ensure
Issue 6: Assets Not Loading (CSS, JavaScript)
Symptoms: Page loads but looks broken, missing styling
Solutions:
-
Check Asset Generation:
- Verify
asset:installcommand ran - Check
public/filesdirectory exists - Ensure assets compiled correctly
- Verify
-
File Permissions:
- Check public directory readable
- Verify asset files present
- Review Apache file access rules
-
Cache Issues:
-
Clear browser cache
-
Set cache busting:
Terminal window ASSET_CACHE_BUST=true -
Restart container
-
-
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:
-
Verify Configuration:
- Check
MAILER_DSNis set correctly - Test SMTP credentials
- Verify mail provider settings
- Check
-
Check Email Logs:
- View application logs for mail errors
- Monitor email queue status
- Check for authentication failures
-
Run Mail Queue:
Terminal window php bin/console messenger:consume async -
Sender Verification:
- Check
MAILER_FROM_ADDRESSis valid - Verify domain DNS records (SPF, DKIM)
- Test with known email
- Check
Issue 8: Memory Limit Errors
Symptoms: “Allowed memory size exceeded” errors
Solutions:
-
Increase Memory Limit:
Terminal window # Set higher PHP memory limitMEMORY_LIMIT=512M -
Upgrade Resources:
- Increase container RAM in Klutch.sh
- Monitor actual memory usage
- Profile code for memory leaks
-
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:
-
Check Permissions:
- Verify user has media permissions
- Check file/folder ownership
- Ensure execute permissions on directories
-
Disk Space:
- Verify persistent volume has space
- Monitor media directory size
- Archive or delete old files if needed
-
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:
-
Check Build Logs:
- Review Klutch.sh deployment logs
- Look for specific error messages
- Check Dockerfile syntax
-
Database Migrations:
- If migrations fail, deployment fails
- Verify database is accessible
- Test migrations locally first
-
Dependencies:
- Ensure all Composer dependencies install
- Check for private repositories
- Verify dependency versions
-
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
- Go to your Contao app in Klutch.sh dashboard
- Navigate to Domains
- Click “Add Custom Domain”
- Enter your domain (e.g.,
www.example.com) - Save
Step 2: Configure DNS
Update your domain provider DNS records:
Type: CNAMEName: wwwValue: example-app.klutch.shTTL: 3600For root domain (@):
Type: CNAME (if supported by provider)Value: example-app.klutch.shIf 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:
- Log in to Contao backend
- Go to System → Settings → Site Configuration
- Set the site domain to your custom domain
- Save changes
- Clear cache
Step 4: Verify Setup
-
Wait for DNS propagation (up to 1 hour)
-
Test domain resolution:
Terminal window nslookup www.example.com -
Verify HTTPS certificate is active
-
Test site loads correctly on custom domain
Production Best Practices
Backup Strategy
What to Backup:
- Database (complete database dump)
- Files directory (all uploads and media)
- 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:
# MySQL backupmysqldump -u contao_user -p contao_db | gzip > /backups/contao-$(date +%Y%m%d).sql.gz
# PostgreSQL backuppg_dump postgresql://contao_user:password@host/contao_db | gzip > /backups/contao-$(date +%Y%m%d).sql.gz
# Files backuptar -czf /backups/contao-files-$(date +%Y%m%d).tar.gz /var/www/html/filesRestore 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
- Contao Official Website
- Contao Documentation
- Contao GitHub Repository
- Contao Case Studies
- Klutch.sh Official Website
- Klutch.sh Dashboard
- Klutch.sh Documentation
- Klutch.sh Custom Domains Guide
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!