Self-Hosting a WordPress Stack with Coolify

Team 6 min read

#wordpress

#coolify

#self-hosting

#docker

#devops

Self-hosting WordPress gives you full control over performance, security, and costs. Coolify makes it much simpler by providing a PaaS-like dashboard on top of Docker, letting you deploy and manage applications, databases, networking, and TLS with minimal ops toil.

This guide walks you through deploying a production-ready WordPress stack on a single VPS using Coolify, including database, persistent storage, HTTPS, backups, and performance tuning.

What You Will Build

  • WordPress running in Docker, managed by Coolify
  • A MySQL or MariaDB database with persistent storage
  • Optional Redis for object caching
  • Automatic HTTPS via reverse proxy (Traefik)
  • Domain routing, environment variables, and logs
  • Backup options and an update workflow

Prerequisites

  • A VPS (2 vCPU, 4 GB RAM minimum recommended; 4 vCPU, 8 GB RAM for busy sites)
  • A domain and ability to create DNS records
  • Ports 80 and 443 open to the internet, and 22 for SSH
  • Ubuntu 22.04+ or Debian 12 commonly used
  • A non-root user with sudo and SSH key access

Optional but recommended:

  • A transactional email provider (e.g., Postmark, Mailgun) for WordPress emails
  • An S3-compatible bucket for backups (e.g., Backblaze B2, Wasabi)

Baseline Server Setup

  • Create a non-root user and harden SSH (key-based auth, disable root login).
  • Enable a firewall:
    • UFW: allow 22, 80, 443; deny others.
  • Keep the system updated:
    • Debian/Ubuntu: sudo apt update && sudo apt upgrade -y
  • Install Docker if not already installed (Coolify can handle it during setup).

Install Coolify

Coolify provides a one-liner installer that sets up the platform and its reverse proxy. Review scripts before running in production.

Example:

curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash

After installation:

  • The Coolify dashboard typically runs on port 8000. Access it at:
    • http://YOUR_SERVER_IP:8000
  • Create the admin account and finish the initial wizard.
  • You can later attach a domain to the Coolify dashboard itself if desired.

Tip: Coolify uses Docker under the hood and a reverse proxy (Traefik) to manage TLS automatically via Let’s Encrypt.

Create or Connect Your Environment

For a single VPS deployment:

  • In Coolify, use the “Local Docker” environment (the default on the server where Coolify is installed).
  • Keep the default internal network unless you have special isolation requirements.

Provision the Database

  1. In Coolify, add a new Service -> Database -> choose MySQL 8 or MariaDB.
  2. Configure:
    • Persistent volume:
      • MySQL: /var/lib/mysql
      • MariaDB: /var/lib/mysql
    • Set root password and create an application user and database (or plan to create them later).
    • Keep this database internal (do not expose a public port). WordPress will connect over the internal Docker network.
  3. Deploy the database service and wait until it’s healthy.

Record the connection details you’ll use in WordPress:

  • Host: the service name in Coolify (e.g., mysql:3306)
  • User, Password, Database name
  1. Add a new Service -> Cache -> Redis.
  2. Persistent volume: /data
  3. Keep it internal and deploy.
  4. You will later enable a WordPress plugin for Redis object caching and point it at the Redis host (e.g., redis:6379).

Deploy WordPress

Coolify often includes a one-click WordPress template. If not, add a new Application and use the official Docker image:

  • Image: wordpress:6-php8.2-apache (or a pinned version you prefer)
  • Internal port: 80
  • Persistent volume: /var/www/html

Environment variables (adjust names for your DB):

  • WORDPRESS_DB_HOST: mysql:3306
  • WORDPRESS_DB_USER: app_user
  • WORDPRESS_DB_PASSWORD: strongpassword
  • WORDPRESS_DB_NAME: app_db

Security and quality-of-life variables:

  • WORDPRESS_CONFIG_EXTRA: use this to append PHP constants to wp-config.php. Example:
    define('FORCE_SSL_ADMIN', true);
    define('DISALLOW_FILE_EDIT', true);
    define('WP_MEMORY_LIMIT', '256M');
    define('WP_MAX_MEMORY_LIMIT', '512M');

If you intend to use Redis:

  • Add: WP_REDIS_HOST=redis
  • After WordPress is up, install and enable a Redis object cache plugin.

Configure the Domain and HTTPS

  1. Create a DNS A record for your site (e.g., www.example.com) pointing to your server IP.
  2. In the WordPress application settings in Coolify:
    • Set the domain to www.example.com.
    • Enable HTTPS/auto TLS. Ensure your ACME email is configured in Coolify’s proxy settings.
  3. Redeploy the application if required. Traefik will obtain and renew a Let’s Encrypt certificate automatically.

Once HTTPS is active, set WordPress Address and Site Address (in Settings -> General) to the final HTTPS URL.

SMTP for Outbound Email

WordPress needs SMTP for reliable email delivery. Use a plugin such as WP Mail SMTP and add credentials from your email provider. Alternatively, you can define constants via WORDPRESS_CONFIG_EXTRA, but plugins are usually simpler.

Backups

You need both database and media backups.

Approaches:

  • Database dumps: schedule mysqldump inside a small sidecar or via a cron job on the host, then upload to S3 with a tool like rclone or restic.
  • Volume snapshots: use restic to back up the WordPress /var/www/html volume and database volume to S3-compatible storage.
  • Offsite is critical. Store at least 7–30 days of daily backups. Test restore on a separate environment.

Example database dump script (run via cron on the host or a maintenance container):

mysqldump -h mysql -u app_user -p'SECRET' app_db \
  | gzip > /backups/app_db-$(date +%F).sql.gz

Updates and Maintenance

  • Pin image tags (e.g., wordpress:6.6.2-php8.2-apache) for predictability. Avoid latest in production.
  • To update WordPress core and PHP runtime, change the image tag and redeploy, then run WordPress updates inside the admin.
  • Update plugins and themes regularly. Remove unused ones.
  • Monitor logs in Coolify:
    • Application logs for PHP/Apache
    • Database logs for slow queries
  • Resource monitoring: watch CPU, RAM, and disk I/O. Scale the VPS or add caching/CDN as traffic grows.

Performance Tips

  • Enable a page cache plugin (e.g., a lightweight full-page cache). Consider a CDN for static assets.
  • Enable Redis object cache for database offload.
  • Use optimized images and lazy loading.
  • Consider moving media to object storage with a plugin that supports S3-compatible providers.
  • Set appropriate PHP memory limits and opcache defaults via WORDPRESS_CONFIG_EXTRA.

Security Checklist

  • Force HTTPS and set HSTS at the proxy level if appropriate.
  • Set DISALLOW_FILE_EDIT true to disable theme/plugin editor.
  • Keep WordPress, themes, plugins updated.
  • Use strong, unique passwords and a login rate limiter or WAF.
  • Limit admin accounts; use least privilege.
  • Regular backups and tested restore procedures.

Troubleshooting

  • 502/Bad Gateway:
    • Check if the WordPress container is healthy and listening on port 80.
    • Verify domain points to the server and that the app has the correct domain in Coolify.
  • Database connection errors:
    • Confirm service name and port (e.g., mysql:3306).
    • Validate credentials and that the DB is ready.
  • SSL issues:
    • Ensure DNS has propagated and port 80 is open for HTTP-01 challenges.
  • Permission errors on uploads:
    • Ensure the /var/www/html volume is writable by the container’s web user.
  • Memory exhaustion:
    • Increase PHP memory limit; add swap; upgrade VPS resources.

Going Further

  • Staging environment: clone your stack in Coolify with a different domain and database to test updates safely.
  • GitOps: containerize a theme or plugin development workflow and auto-deploy via Coolify.
  • Multi-site: the official WordPress image supports multisite with extra configuration; ensure domain mapping and wildcard DNS as needed.

With Coolify handling orchestration, networking, and TLS, you can self-host WordPress with a clear, repeatable workflow and a clean path to scaling as your site grows.