Free WordPress Hosting: A Step-by-Step Guide to Deploying with Docker and Fly.io
Learn how to containerise and deploy a scalable, production-ready WordPress site on a modern cloud platform. Say goodbye to high hosting fees and take

Full Stack Engineer (TypeScript, React.js, Node.js) and Stripe Implementation Architect with 6+ years of experience, leveraging AI-native workflows (Cursor, Claude Code) to deliver scalable solutions to improve user interactions and business processes. Proven track record of mentoring 200+ developers across 3 continents and implementing enterprise payment solutions. Specialist in clean architecture and modern stacks.
Are you tired of paying hefty monthly fees for managed WordPress hosting? Do you want more control over your website's environment? If so, you're in the right place. This guide will walk you through setting up a powerful, scalable, and incredibly cost-effective WordPress site using Docker and the cloud platform Fly.io.
For many, "self-hosting" sounds intimidating, bringing to mind complex server management and late-night troubleshooting. However, by containerising our application with Docker, we can package everything WordPress needs into a neat, reproducible box. And by deploying it on a platform like Fly.io, we get the benefits of a modern cloud infrastructure—like global distribution and easy scaling—often for a fraction of the cost of traditional hosting. In fact, with Fly.io's generous free tier, your hosting could be completely free.
This guide is based on the Free Tribe Network's own open-source setup. Let's get started.
What You'll Need
A Fly.io account.
flyctlThe Fly.io command-line tool, installed.Docker Desktop is installed and running.
Basic familiarity with your computer's terminal (command line).
The Two-Part Harmony: WordPress + Database
A standard WordPress installation has two main components:
The WordPress Application: This includes the PHP code, themes, and plugins that make up your site.
The Database: This is where all your content—posts, pages, user information, and settings—is stored.
We will deploy these as two separate, but connected, applications on Fly.io. This is a best practice that makes the system more robust and easier to manage.
Part 1: The Database Backbone (MySQL)
First, we'll set up our MySQL database.
Launch the Database App: We'll start by telling Fly.io to create a new app using the official
mysql:8Docker image.fly launch --no-deploy --image mysql:8 --name your-app-name-db--no-deploy: We don't want to deploy it just yet; we have some configuration to do first.--name: Give your database a unique name. It's good practice to append-dbto it.
Create a Persistent Volume: By default, a Fly.io app's filesystem is ephemeral. To store our database data permanently, we need to attach a volume.
fly volumes create mysqldata --size 10This creates a 10GB persistent volume named
mysqldata.Configure
fly.toml: Thefly launchcommand created afly.tomlfile. Open it and ensure it contains the following, paying close attention to the[mounts]and[env]sections.app = 'your-app-name-db' primary_region = 'jnb' # Or your preferred region [build] image = 'mysql:8' [mounts] source = "mysqldata" destination = "/var/lib/mysql" # The standard location for MySQL data [env] MYSQL_DATABASE = "wordpress" MYSQL_USER = "wp_user"The
[mounts]section tells Fly to mount the volume we created to the correct directory inside the container.The
[env]section sets up the initial database name and user.
Set Your Secrets: We need to set a password for the database user and the root user. These are stored as encrypted secrets in Fly.io, not in the
fly.tomlfile.fly secrets set MYSQL_PASSWORD='<choose-a-strong-password>' MYSQL_ROOT_PASSWORD='<choose-a-stronger-password>'Deploy! Now, we're ready to deploy our database.
fly deploy
Part 2: The WordPress Frontend
With the database running, we can now set up the main WordPress application.
Create a Project Directory: In a new directory on your local machine, we'll set up the files for our WordPress app.
The
Dockerfile: Create a file namedDockerfile. This file defines our custom WordPress container. We'll use the official WordPress image as a base and add a few tweaks.FROM wordpress:latest # Add CORS configuration for headless/API access COPY cors-config.php /usr/src/wordpress/wp-content/mu-plugins/cors-config.php # Increase default file upload limits COPY uploads.ini /usr/local/etc/php/conf.d/uploads.iniThis setup includes configurations for CORS (useful for headless setups) and increases the file upload size. You'll need to create the
cors-config.phpanduploads.inifiles with your desired settings.Here's mine:
<!-- cors-config.php --> <?php /** * Plugin Name: REST API CORS * Description: Enable CORS for REST API * Version: 1.0 * Author: Free Tribe Network */ add_action('rest_api_init', function() { remove_filter('rest_pre_serve_request', 'rest_send_cors_headers'); add_filter('rest_pre_serve_request', function($value) { header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE'); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Expose-Headers: Link'); header('Access-Control-Allow-Headers: X-WP-Nonce, Content-Type, Authorization'); return $value; }); }, 15);; uploads.ini file_uploads = On memory_limit = 256M upload_max_filesize = 64M post_max_size = 64MLaunch the WordPress App: Just like the database, we'll launch a new Fly.io app.
fly launch --name your-app-name-wp --no-deployCreate a Volume for
wp-content: We need another persistent volume to store theme and plugin files, and user uploads.fly volumes create wp_content --size 10Configure
fly.toml: Thefly.tomlfor our WordPress app is crucial. It's how we connect to our database.app = 'your-app-name-wp' primary_region = 'lhr' # Match your database region if desired [build] dockerfile = "Dockerfile" [mounts] source="wp_content" destination="/var/www/html/wp-content" [env] WORDPRESS_DB_HOST = "your-app-name-db.internal:3306" WORDPRESS_DB_NAME = "wordpress" WORDPRESS_DB_USER = "wp_user"WORDPRESS_DB_HOST: This is the key. It points to the internal network address of our database app. The.internaladdress is a private network address that only your Fly.io apps can access.WORDPRESS_DB_NAMEandWORDPRESS_DB_USERmust match the values you set in the database's[env]section.
Set the Database Password Secret: We'll set the database password as a secret, just like we did for the database app itself. This must be the same password.
fly secrets set WORDPRESS_DB_PASSWORD='<the-same-strong-password-from-before>'Deploy WordPress!
fly deploy
Conclusion: Freedom and Control
That's it! You now have a fully functional, high-performance WordPress site running on a modern cloud platform. You can access it via https://your-app-name-wp.fly.dev.
By moving away from traditional, restrictive hosting, you've not only unlocked significant cost savings but also gained a new level of control. You can now easily scale your resources, deploy changes with a simple fly deploy, and rest easy knowing your application is packaged neatly in a container, ready to be hosted anywhere. Welcome to the future of WordPress hosting.




