[PR #1011] [MERGED] fix(wordpress): route loopback requests through Traefik to fix cURL error 28 timeouts #16319

Closed
opened 2026-07-14 23:19:09 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/Dokploy/templates/pull/1011
Author: @Siumauricio
Created: 7/14/2026
Status: Merged
Merged: 7/14/2026
Merged by: @Siumauricio

Base: canaryHead: fix/wordpress-loopback


📝 Commits (1)

  • af16250 fix(wordpress): route loopback requests through Traefik to fix cURL error 28

📊 Changes

2 files changed (+24 additions, -1 deletions)

View changed files

📝 blueprints/wordpress/docker-compose.yml (+22 -0)
📝 blueprints/wordpress/template.toml (+2 -1)

📄 Description

Problem

Fresh WordPress deployments report two Site Health errors (#128):

  • The REST API encountered an error(http_request_failed) cURL error 28: Connection timed out after 10000 milliseconds
  • Your site could not complete a loopback requestcURL error 28: Connection timed out after 10000 milliseconds

This breaks WP-Cron, the block editor checks, and plugin/theme management.

Root cause

Inside the container, WordPress resolves its own public domain to the server's public IP, so every loopback request (REST API self-check, WP-Cron, Site Health) has to leave the container and hairpin back through the host to Traefik. Whether that works depends entirely on the host's hairpin-NAT/firewall setup — on many VPS/cloud configurations the packets are dropped and the request times out with cURL error 28.

Verified empirically on a live Dokploy deployment by running diagnostics inside the container:

== domain DNS ==
31.220.108.27   compose-...sslip.io      <- resolves to the public IP (hairpin dependency)
== traefik DNS ==
10.100.17.4     dokploy-traefik          <- Traefik IS reachable on the shared Docker network
== http GET via traefik ip (Host: <domain>) ==
HTTP/1.1 302 Found in 0.34s              <- Traefik routes the domain correctly when addressed directly

Fix

At container startup, resolve dokploy-traefik on the shared Docker network and pin <traefik-ip> <domain> in /etc/hosts. Loopback traffic then goes container → Traefik → container entirely inside the Docker network — no hairpin NAT involved — and works for both HTTP and HTTPS (Traefik serves the real certificate).

Details:

  • The resolution runs in a background retry loop (up to 2 min): Dokploy connects Traefik to the per-compose network shortly after the container starts, so a single lookup at t=0 misses it (observed: pinned after 2 tries). Apache startup is never delayed.
  • Graceful no-op if dokploy-traefik is not resolvable — behavior falls back to exactly what it is today.
  • WP_DOMAIN is passed from the template's ${main_domain} so the pinned host always matches the generated domain.

Verification (live deploy on Dokploy)

In-container diagnostics after the fix:

== etc hosts ==
10.100.22.4 compose-...sslip.io          <- pinned to Traefik
== loopback GET http://domain/ ==
HTTP/1.1 200 OK in 0.11s
== loopback GET http://domain/wp-json/ ==
HTTP/1.1 200 OK in 0.05s
== loopback GET http://domain/wp-cron.php ==
HTTP/1.1 200 OK in 0.03s

WordPress's own Site Health loopback test (the exact check from the issue), run as an authenticated admin against the final template:

{"label":"Your site can perform loopback requests","status":"good", ...}

Fresh install flow, external REST API (/wp-json/ → 200) and admin login all verified working. node build-scripts/generate-meta.js --check passes (476 templates validated).

Closes #128

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/Dokploy/templates/pull/1011 **Author:** [@Siumauricio](https://github.com/Siumauricio) **Created:** 7/14/2026 **Status:** ✅ Merged **Merged:** 7/14/2026 **Merged by:** [@Siumauricio](https://github.com/Siumauricio) **Base:** `canary` ← **Head:** `fix/wordpress-loopback` --- ### 📝 Commits (1) - [`af16250`](https://github.com/Dokploy/templates/commit/af162505610181633a70c7f448cff6d3a7039dd8) fix(wordpress): route loopback requests through Traefik to fix cURL error 28 ### 📊 Changes **2 files changed** (+24 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `blueprints/wordpress/docker-compose.yml` (+22 -0) 📝 `blueprints/wordpress/template.toml` (+2 -1) </details> ### 📄 Description ## Problem Fresh WordPress deployments report two Site Health errors (#128): - **The REST API encountered an error** — `(http_request_failed) cURL error 28: Connection timed out after 10000 milliseconds` - **Your site could not complete a loopback request** — `cURL error 28: Connection timed out after 10000 milliseconds` This breaks WP-Cron, the block editor checks, and plugin/theme management. ## Root cause Inside the container, WordPress resolves its own public domain to the **server's public IP**, so every loopback request (REST API self-check, WP-Cron, Site Health) has to leave the container and hairpin back through the host to Traefik. Whether that works depends entirely on the host's hairpin-NAT/firewall setup — on many VPS/cloud configurations the packets are dropped and the request times out with cURL error 28. Verified empirically on a live Dokploy deployment by running diagnostics inside the container: ``` == domain DNS == 31.220.108.27 compose-...sslip.io <- resolves to the public IP (hairpin dependency) == traefik DNS == 10.100.17.4 dokploy-traefik <- Traefik IS reachable on the shared Docker network == http GET via traefik ip (Host: <domain>) == HTTP/1.1 302 Found in 0.34s <- Traefik routes the domain correctly when addressed directly ``` ## Fix At container startup, resolve `dokploy-traefik` on the shared Docker network and pin `<traefik-ip> <domain>` in `/etc/hosts`. Loopback traffic then goes container → Traefik → container entirely inside the Docker network — no hairpin NAT involved — and works for both HTTP and HTTPS (Traefik serves the real certificate). Details: - The resolution runs in a background retry loop (up to 2 min): Dokploy connects Traefik to the per-compose network shortly *after* the container starts, so a single lookup at t=0 misses it (observed: `pinned after 2 tries`). Apache startup is never delayed. - Graceful no-op if `dokploy-traefik` is not resolvable — behavior falls back to exactly what it is today. - `WP_DOMAIN` is passed from the template's `${main_domain}` so the pinned host always matches the generated domain. ## Verification (live deploy on Dokploy) In-container diagnostics after the fix: ``` == etc hosts == 10.100.22.4 compose-...sslip.io <- pinned to Traefik == loopback GET http://domain/ == HTTP/1.1 200 OK in 0.11s == loopback GET http://domain/wp-json/ == HTTP/1.1 200 OK in 0.05s == loopback GET http://domain/wp-cron.php == HTTP/1.1 200 OK in 0.03s ``` WordPress's own Site Health loopback test (the exact check from the issue), run as an authenticated admin against the final template: ```json {"label":"Your site can perform loopback requests","status":"good", ...} ``` Fresh install flow, external REST API (`/wp-json/` → 200) and admin login all verified working. `node build-scripts/generate-meta.js --check` passes (476 templates validated). Closes #128 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-07-14 23:19:09 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/templates#16319