Skip to main content

Install WordPress on Ubuntu Server with Docker — Part 2: Custom Domain, Free HTTPS, Redis Cache and Backups

· 26 min read
Jagdish Kumawat
Founder @ Dewiride

Your WordPress site works, but only on your own network. This part puts it on the real internet with your own domain name and free HTTPS — using a Cloudflare Tunnel, so you never open a single port or touch your router. Then we add a Redis cache, set up backups, and finish with a clean removal.

This is Part 2 of a 2-part series.

  1. Part 1: Run WordPress with Docker Compose
  2. Part 2: Custom Domain, Free HTTPS, Redis Cache and Backups (you are here)

Introduction

At the end of Part 1 you had WordPress and MariaDB running in two containers, reachable at an address like http://192.168.1.50:8080. Fine for building. Not something you can hand to anyone.

To put a site online, the traditional advice is: point a domain at your server's public IP, open ports 80 and 443 on your router, and run something like Certbot to get a certificate. That works — on a rented cloud server with its own public address.

On a machine at home or in an office, it very often does not, for reasons that have nothing to do with your skill:

  • Most home internet connections put you behind CGNAT, meaning you share one public address with many other customers. There is no address that belongs to you, so there is nothing to point a domain at.
  • Many providers block incoming connections on ports 80 and 443 on residential plans.
  • Even where it works, opening those ports exposes the machine to the entire internet's background noise of automated attacks.

A Cloudflare Tunnel sidesteps all three. Instead of the internet connecting in to your server, a small program on your server makes an outbound connection out to Cloudflare and holds it open. Visitors reach Cloudflare; Cloudflare passes requests down that existing connection. Your router needs no changes, and your server needs no open ports at all.

note

Everything in this guide was performed on a real Ubuntu 26.04 LTS server sitting on an ordinary home connection behind CGNAT, with no router configuration whatsoever. The site really did go live, and the screenshots are the actual results. Software versions: WordPress 7.0.4, MariaDB 11.8, Redis 8.10, PHP 8.4.24.

Throughout the commands you will see wp.example.com, which is a placeholder — swap in your own domain. The screenshots show the genuine domain used while testing, so the two will not match exactly. That is expected.

What You Will Build

By the end of this part:

  • Your site will be live at your own domain over HTTPS, with a valid certificate.
  • Your server will have zero ports exposed — even the 8080 from Part 1 is closed.
  • You will reach your admin panel at https://your-domain/wp-admin, and know how to recover it if you are ever locked out.
  • A Redis container will cache database queries so pages build faster.
  • You will have WP-CLI available for maintenance tasks.
  • You will have working backups of both the database and your files.
  • You will know how to remove the whole thing without a trace.

Prerequisites

  • Part 1 completed — WordPress running in Docker on your Ubuntu Server.
  • A domain name you own. Any registrar is fine.
  • A free Cloudflare account. No paid plan is needed for any of this.
  • Your domain's DNS managed by Cloudflare. If it is not yet, add the site in the Cloudflare dashboard and change the nameservers at your registrar to the two Cloudflare gives you.
warning

If your domain currently has DNSSEC enabled, turn it off at your existing DNS provider before moving nameservers to Cloudflare, and wait about an hour. Moving a signed domain without doing this makes the whole domain stop resolving — every subdomain, plus email. Cloudflare can re-enable DNSSEC for you afterwards.

How a Cloudflare Tunnel Works

Worth understanding before you click anything, because it explains why there is nothing to open.

Normally a visitor's browser connects to your server. Something must therefore accept incoming connections, which is what port forwarding arranges and what CGNAT prevents.

With a tunnel, a small program called cloudflared runs on your server and dials out to Cloudflare — the same kind of outbound connection your browser makes when loading any website. Outbound connections are never blocked by CGNAT and need no router rules. That connection stays open.

When someone visits your site:

  1. Their browser looks up your domain and gets a Cloudflare address.
  2. They connect to Cloudflare, which handles HTTPS and the certificate.
  3. Cloudflare sends the request down the already-open tunnel to cloudflared.
  4. cloudflared passes it to your WordPress container and returns the reply.

Your server is never addressed directly from the internet. It is not merely firewalled — there is no route to it at all.

Step 1: Create the Tunnel in Cloudflare

Sign in at one.dash.cloudflare.com and go to Networks → Tunnels & Mesh, then click Create a tunnel.

Choose the Cloudflared option.

The Cloudflare tunnel type selection screen with the Cloudflared option and its Select Cloudflared button

Give the tunnel a name you will recognise later — wordpress-blog is a good choice — and save it.

Cloudflare then shows you install commands for various systems. You do not need to run any of them. We are going to run cloudflared as a container instead. What you do need is the long string of letters after --token in that command. Click the copy button next to the command and keep it on your clipboard.

danger

That token is a password for your tunnel. Anyone who has it can route traffic through it. Never paste it into a blog post, a screenshot, a public repository, or a support forum. We store it in the .env file, which stays on your server.

Step 2: Add the Token to Your .env File

Back on your server, in the ~/wordpress folder, add the token you just copied to your .env file:

Ubuntu Server Terminal
cd ~/wordpress
nano .env

Add this line at the bottom, replacing the placeholder with your real token:

.env
TUNNEL_TOKEN=paste-your-very-long-token-here

It will be a long, unbroken string of letters and numbers — several hundred characters. Paste it all on one line, with no spaces and no line breaks.

Save with Ctrl+O, Enter, then exit with Ctrl+X.

Confirm the file is still private to you:

Ubuntu Server Terminal
chmod 600 .env

Step 3: Add cloudflared, Redis and WP-CLI to Your Stack

Open your Compose file:

Ubuntu Server Terminal
nano compose.yaml

Replace the whole file with the version below. Three services are new, and there is one important deletion.

The full compose.yaml file with db, redis, wordpress, cloudflared and wpcli services defined

compose.yaml
name: wordpress

services:
db:
image: mariadb:11.8
restart: unless-stopped
environment:
MARIADB_DATABASE: ${WORDPRESS_DB_NAME}
MARIADB_USER: ${WORDPRESS_DB_USER}
MARIADB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s

redis:
image: redis:8-alpine
restart: unless-stopped
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

wordpress:
image: wordpress:7.0-php8.4-apache
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
volumes:
- wp_data:/var/www/html

cloudflared:
image: cloudflare/cloudflared:latest
restart: unless-stopped
depends_on:
- wordpress
command: tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}

wpcli:
image: wordpress:cli-php8.4
profiles: ["cli"]
user: "33:33"
depends_on:
db:
condition: service_healthy
environment:
HOME: /tmp
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
volumes:
- wp_data:/var/www/html

volumes:
db_data:
wp_data:
redis_data:

What Changed, and Why

The deletion — the ports: block is gone. In Part 1 the wordpress service published "8080:80". It no longer publishes anything. Traffic now arrives through the tunnel, which reaches WordPress over Docker's internal network. Closing 8080 means that even on your own network, nothing can reach the site except through Cloudflare. This is the single biggest security improvement in this guide, and it costs one deleted line.

redis — an in-memory store. WordPress normally asks the database the same questions on every page load; Redis remembers the answers. --maxmemory 256mb caps its memory use, and allkeys-lru tells it to discard the least recently used entries when full, so it can never grow without limit.

cloudflared — the tunnel program. Its whole configuration is that one command: line. --no-autoupdate stops it updating itself inside the container; you update it like any other image, by pulling a new one.

wpcli — WP-CLI, the official command-line tool for WordPress. Note profiles: ["cli"], which means it does not run as a background service. It only runs when you explicitly ask for it, does its job, and exits. user: "33:33" runs it as the same web-server user that owns the files, so anything it creates has the right ownership.

tip

You may have seen guides that set WORDPRESS_CONFIG_EXTRA in Compose to add settings like WP_HOME. That variable only takes effect when the image creates wp-config.php for the very first time. Because Part 1 already created that file, adding it now does nothing at all — a genuinely confusing failure, because Compose reports no error. Step 5 uses WP-CLI instead, which edits the real file and works every time.

Step 4: Start the New Stack

Ubuntu Server Terminal
docker compose up -d

Docker Compose creating the redis volume and starting the redis, wordpress and cloudflared containers

Check what is running:

Ubuntu Server Terminal
docker compose ps

The docker compose ps output showing cloudflared, db, redis and wordpress running with no published ports

Look carefully at the PORTS column. Every entry is a bare internal port — 3306/tcp, 6379/tcp, 80/tcp — and not one has 0.0.0.0: in front of it. That prefix is what "published to the outside world" looks like, and it has gone. Your server is now running a public website with no open ports whatsoever.

Now confirm the tunnel actually connected:

Ubuntu Server Terminal
docker compose logs cloudflared | grep "Registered tunnel connection"

Cloudflared log lines showing four registered tunnel connections over the QUIC protocol

Four Registered tunnel connection lines is exactly right. cloudflared deliberately opens several connections to different Cloudflare data centres so your site stays up if one has a problem. If you see these, the hard part is done.

Step 5: Point Your Domain at the Tunnel

Back in the Cloudflare dashboard, open your tunnel and go to Published application routes, then Add a published application route.

The Cloudflare published application route form with subdomain wp, domain example.com, service type HTTP and URL wordpress:80

Fill it in:

  • Subdomainwp (or www, or leave blank to use the bare domain).
  • Domain — pick your domain from the list.
  • Path — leave empty, so every page is served.
  • Service TypeHTTP.
  • URLwordpress:80.

That last field deserves a moment. It is not an internet address and not your server's IP. wordpress is the service name from your Compose file, and containers on the same Compose network find each other by service name. You are telling cloudflared to hand requests to its neighbour container.

Note that HTTP here is correct and safe: this is traffic inside your server between two containers, and it never leaves the machine. The public half of the journey is HTTPS, handled by Cloudflare.

Click Save.

The saved route showing wp.example.com mapped to http://wordpress:80 with a catch-all 404 rule

Cloudflare creates the DNS record for you automatically — there is no separate DNS step.

Step 6: Tell WordPress Its New Address

One thing still points at the old address. WordPress stored its own URL in the database during the Part 1 install, so it still believes it lives at http://192.168.1.50:8080. Left alone, logging in will bounce you back to the old address.

Fix it with WP-CLI. Replace wp.example.com with your real domain:

Ubuntu Server Terminal
docker compose run --rm wpcli config set WP_HOME https://wp.example.com
docker compose run --rm wpcli config set WP_SITEURL https://wp.example.com

wp config set writes these as constants into wp-config.php. Constants beat the values stored in the database, which is the safer approach: if anything ever goes wrong with the domain you can change one line in a file rather than trying to log in to a site you cannot reach.

The first run downloads the WP-CLI image, so give it a moment. Each command prints a Success: line.

Step 7: Visit Your Live Site

Open your domain in a browser.

The WordPress site loading over HTTPS at the custom domain, showing the site title and the Hello world post

There is your site, on the public internet, at your own domain, with a padlock in the address bar.

You can confirm the details from the server too:

Ubuntu Server Terminal
curl -sI https://wp.example.com | head -7

The curl output showing HTTP/2 200, server cloudflare and x-powered-by PHP 8.4.24

Three things worth reading in that response:

  • HTTP/2 200 — success, over a modern encrypted connection.
  • server: cloudflare — the request was served through Cloudflare's network.
  • x-powered-by: PHP/8.4.24 — and the page itself came from your container.

The certificate is issued and renewed by Cloudflare automatically. There is nothing to remember and nothing that expires on you.

Step 8: Log In to Your Admin Panel at the New Address

Your site moved, so the address you used to manage it has moved too. The old http://192.168.1.50:8080/wp-admin will no longer work — and that is deliberate, because you closed that door in Step 3.

From now on, the admin panel lives at your domain with /wp-admin on the end:

Browser address bar
https://wp.example.com/wp-admin

Replace wp.example.com with your own domain. Two other addresses reach the same place, and all are worth knowing:

AddressWhat it does
https://wp.example.com/wp-adminThe dashboard. Sends you to the login page first if you are signed out
https://wp.example.com/wp-login.phpThe login page directly
https://wp.example.com/wp-admin/options-general.phpJumps straight to Settings → General

Open the first one. Because you are signed out on this new address, WordPress shows the login screen.

The WordPress login page served over HTTPS at the custom domain, with the username filled in and the password hidden

Enter the username and password you chose during the Part 1 installer — they have not changed. Moving the site to a new address does not affect your account, because the user record lives in the database, which we never touched.

Tick Remember Me if this is your own computer, then click Log In.

The WordPress dashboard loaded over HTTPS at the custom domain, showing the admin menu and welcome panel

You are in, and this time over HTTPS at your own domain. This is where you write posts, add pages, install plugins and change your theme.

tip

Bookmark https://wp.example.com/wp-admin now and delete any old bookmark pointing at the IP address. If you ever forget the address, it is always your site's address with /wp-admin added to the end.

If the Login Page Sends You in Circles

Two problems account for almost every login difficulty after a domain move, and both have quick answers:

  • You get bounced back to the old IP address. WP_HOME and WP_SITEURL were not set. Re-run the two wp config set commands from Step 6 and try again.

  • You forgot the password. Lost your password? needs working email, which a fresh server does not have. Set a new one directly instead:

    Ubuntu Server Terminal
    docker compose run --rm wpcli user list
    docker compose run --rm wpcli user update siteadmin --user_pass='YourNewStrongPassword'

    The first command lists your accounts so you can confirm the username; the second sets a new password immediately. This works even when email does not, which is why WP-CLI is worth having.

Confirming WordPress Knows Its Own Address

While you are here, go to Settings → General in the left-hand menu.

The WordPress General Settings page showing the WordPress Address and Site Address fields greyed out and set to the HTTPS domain

WordPress Address (URL) and Site Address (URL) should both show your https:// domain, and both will be greyed out so you cannot edit them. That is correct and is exactly what you want: because you set them as constants in wp-config.php in Step 6, they can no longer be changed by accident from the dashboard — which is a common way people lock themselves out of a WordPress site.

Notice also the Redis entry at the bottom of the Settings submenu in that screenshot. That appeared when you installed the plugin, and it is where the next step ends up.

Step 9: Turn On the Redis Cache

Redis is running, but WordPress does not use it until you install a plugin that knows how.

Ubuntu Server Terminal
docker compose run --rm wpcli plugin install redis-cache --activate

Now tell WordPress where Redis is, and which client library to use:

Ubuntu Server Terminal
docker compose run --rm wpcli config set WP_REDIS_HOST redis
docker compose run --rm wpcli config set WP_REDIS_CLIENT predis

WP_REDIS_HOST redis is the service name again. The second line matters more than it looks: the official WordPress image does not include PHP's compiled redis extension, so the plugin's default client cannot connect. predis is a pure-PHP client bundled with the plugin, and it works with the standard image and no custom build. If you skip this line you get a confusing "Redis server is unreachable" error even though Redis is running perfectly.

Now switch the cache on:

Ubuntu Server Terminal
docker compose run --rm wpcli redis enable

And check it:

Ubuntu Server Terminal
docker compose run --rm wpcli redis status

WP-CLI reporting status connected, client Predis, drop-in valid and ping PONG

Status: Connected and Ping: PONG mean it is working.

You can confirm the same thing in the admin panel. Go to https://wp.example.com/wp-admin, then click Settings in the left-hand menu and choose Redis from the list that appears underneath it. (Direct link: https://wp.example.com/wp-admin/options-general.php?page=redis-cache.)

The Redis Object Cache settings page showing status connected, Redis reachable, host redis and port 6379

Three green ticks — Status: Connected, Filesystem: Writeable, Redis: Reachable — mean everything is wired up. Below them you can see the connection WordPress is using: client Predis, host redis, port 6379. The Flush Cache button empties the cache, which is occasionally useful after changing a theme if you see stale content.

Want proof it is really caching? Load your site, then count the stored entries:

Ubuntu Server Terminal
docker compose exec redis redis-cli DBSIZE

A number in the dozens means WordPress is storing answers rather than re-asking the database every time.

Step 10: Set Up Backups

Containers are disposable. Your data is not, and Docker does not back it up for you. This section is the one to actually do rather than bookmark.

There are two things to save: the database and your files (uploads, themes, plugins).

Make a folder, then dump the database:

Ubuntu Server Terminal
mkdir -p ~/backups

docker compose exec -T db sh -c 'exec mariadb-dump -u root -p"$MARIADB_ROOT_PASSWORD" --single-transaction --all-databases' > ~/backups/db-$(date +%F).sql

That command looks dense, so here it is in pieces:

  • docker compose exec -T db runs a command inside the database container.
  • sh -c '...' runs it through a shell inside the container. This matters: it means $MARIADB_ROOT_PASSWORD is read from the container's own environment, so your password never appears in your command history on the host.
  • --single-transaction takes a consistent snapshot without locking the site.
  • > ~/backups/db-$(date +%F).sql saves it with today's date in the name.

Now the files:

Ubuntu Server Terminal
docker run --rm -v wordpress_wp_data:/data:ro -v ~/backups:/backup alpine \
tar czf /backup/files-$(date +%F).tar.gz -C /data .

This starts a tiny temporary container, attaches your WordPress volume read-only (:ro), compresses its contents into your backups folder, and disappears.

A directory listing showing the dated database dump and the compressed files archive

warning

A backup sitting on the same server is not a backup — it dies with the machine. Copy these files somewhere else regularly, using scp, rsync, or any cloud storage tool. Test a restore at least once, because an untested backup is only a hope.

Restoring

To restore the database from a dump:

Ubuntu Server Terminal
docker compose exec -T db sh -c 'exec mariadb -u root -p"$MARIADB_ROOT_PASSWORD"' < ~/backups/db-2026-08-17.sql

To restore the files:

Ubuntu Server Terminal
docker run --rm -v wordpress_wp_data:/data -v ~/backups:/backup alpine \
tar xzf /backup/files-2026-08-17.tar.gz -C /data

Then restart the site with docker compose restart.

Step 11: Keeping It Updated

Three separate things to keep current, in decreasing order of importance.

Plugins and themes — update from the WordPress dashboard as usual, or from the command line:

Ubuntu Server Terminal
docker compose run --rm wpcli plugin update --all
docker compose run --rm wpcli theme update --all

WordPress, MariaDB, Redis — change the version in compose.yaml, then:

Ubuntu Server Terminal
docker compose pull
docker compose up -d

cloudflared — it uses the latest tag, so:

Ubuntu Server Terminal
docker compose pull cloudflared
docker compose up -d cloudflared

Always take a backup before changing a version. Your data lives in volumes and is not touched by an image swap, but "not touched" and "recoverable if something surprises you" are different guarantees.

Step 12: Removing Everything Cleanly

This was the original promise, so here it is in full.

Stop and remove the containers, keeping all your content:

Ubuntu Server Terminal
cd ~/wordpress
docker compose down

Remove the containers and permanently delete the site and database:

Ubuntu Server Terminal
docker compose down -v

Remove the downloaded images:

Ubuntu Server Terminal
docker rmi wordpress:7.0-php8.4-apache mariadb:11.8 redis:8-alpine \
cloudflare/cloudflared:latest wordpress:cli-php8.4

Remove the project folder:

Ubuntu Server Terminal
cd ~ && rm -rf ~/wordpress

And in Cloudflare, delete the tunnel (Networks → Tunnels & Mesh → your tunnel → Delete) and remove the DNS record it created.

Your Ubuntu server is now exactly as it was before Part 1. No Apache, no PHP, no MySQL, no stray config files, no system users, and no ports opened.

danger

docker compose down -v permanently deletes your database and uploaded files. There is no undo. Take a backup first unless you are certain.

Common Mistakes

MistakeWhat you'll seeFix
Leaving WORDPRESS_CONFIG_EXTRA in Compose and expecting it to workNo error, but the settings simply never appearUse wpcli config set — the variable only applies when wp-config.php is first created
Skipping WP_REDIS_CLIENT predisRedis server is unreachable despite Redis running fineThe official image has no redis PHP extension; Predis is bundled with the plugin
Putting localhost:8080 in the Cloudflare service URL502 errors from CloudflareUse wordpress:80 — the service name, not localhost, because cloudflared is its own container
Forgetting to update WP_HOME / WP_SITEURLLogin redirects you back to the old IP addressRun the wp config set commands in Step 6
Pasting the tunnel token into a public placeAnyone can route traffic through your tunnelKeep it in .env; if exposed, use Refresh token in Cloudflare
Moving nameservers to Cloudflare with DNSSEC still onThe entire domain stops resolvingDisable DNSSEC first, wait an hour, then move

Troubleshooting

ProblemCauseFix
Cloudflare shows Error 1033The tunnel is not connecteddocker compose logs cloudflared and look for Registered tunnel connection; check the token in .env
502 Bad Gatewaycloudflared cannot reach WordPressConfirm the service URL is wordpress:80 and that docker compose ps shows wordpress running
Site loads but CSS and images are missingWordPress still thinks it lives at the old addressRe-run the Step 6 wp config set commands
Redirect loop on the login pageWordPress cannot tell the request arrived over HTTPSThe official image handles this via X-Forwarded-Proto; make sure WP_HOME/WP_SITEURL both start with https://
Old admin bookmark http://SERVER_IP:8080/wp-admin no longer opensCorrect — port 8080 was closed in Step 3Use https://your-domain/wp-admin and update your bookmark
Forgot the admin password, and password reset email never arrivesA fresh server cannot send emailSet a new password directly: docker compose run --rm wpcli user update USERNAME --user_pass='NewPassword'
Forgot which username you createdIt is stored in the database, not in any filedocker compose run --rm wpcli user list shows every account
Site Address fields are greyed out in Settings → GeneralExpected — they are set as constants in wp-config.phpTo change them, use wpcli config set WP_HOME ... and WP_SITEURL
wp redis status says unreachableMissing Predis client settingdocker compose run --rm wpcli config set WP_REDIS_CLIENT predis
DNS record exists but the domain does not loadDNS still propagating, or the record is not proxiedWait a few minutes; the record Cloudflare creates should be proxied (orange cloud)
WP-CLI warns it cannot write /.wp-cli/cache/The CLI container has no home directoryAdd HOME: /tmp to the wpcli service, as in the file above

Frequently Asked Questions

Does a Cloudflare Tunnel cost anything?

No. Tunnels are included on Cloudflare's free plan, with no bandwidth charge for normal website traffic. You only need to own a domain.

Is this less secure than opening ports myself?

It is considerably more secure for a home server. Your machine accepts no incoming connections at all, so the constant background scanning of the internet cannot reach it. Cloudflare also absorbs denial-of-service traffic before it ever gets near you. The trade-off is that your traffic passes through Cloudflare, who can therefore see it — the same trade-off as using any CDN.

Will this work behind CGNAT, or on mobile broadband?

Yes. That is the main reason to choose it. The tunnel only needs an outbound connection, which is exactly what CGNAT permits. This guide was written on a CGNAT connection where port forwarding was impossible.

How do I get into the WordPress admin panel now?

Add /wp-admin to your site's address — https://your-domain/wp-admin — and sign in with the username and password you created during the Part 1 installer. Those credentials did not change when the site moved. The old http://SERVER_IP:8080/wp-admin no longer works, because that port is now closed.

Can I use the bare domain instead of a subdomain?

Yes — leave the Subdomain field empty when creating the route and it will serve example.com directly.

Can I host several sites through one tunnel?

Yes. Add another published application route with a different hostname, pointing at a different container. One cloudflared can serve many sites.

Do I still need to back up if Cloudflare is in front?

Absolutely. Cloudflare delivers your site; it does not store it. Your posts, images and database live only in your Docker volumes. If those are lost and you have no backup, the site is gone.

Is Redis worth it for a small site?

For a brand-new site with a handful of posts, honestly, you would struggle to notice. It becomes worthwhile as your content and plugin count grow, and it costs very little to have running from the start.

What happens if my home internet restarts?

cloudflared reconnects by itself, and restart: unless-stopped means Docker restarts the containers when the machine boots. The site returns without you doing anything.

Conclusion

Across both parts you have built something genuinely respectable: a real WordPress site, running in containers on your own hardware, published to the internet at your own domain with valid HTTPS, cached with Redis, backed up, and — crucially — removable with a single command.

You did it without installing Apache, PHP, or MySQL on the host. Without a control panel. Without opening a single port on your router. And without paying for hosting.

The pattern generalises, too. Any web application you can run in a container can be published the same way: add a service, add a route, and it is online.


Previous: ← Part 1: Run WordPress with Docker Compose

The full series:

  1. Run WordPress with Docker Compose
  2. Custom Domain, Free HTTPS, Redis Cache and Backups

Additional Resources


Video Tutorial

Coming soon!

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.