Caddy on docker wordpress loopback

I have a docker stack consisting of caddy and wordpress currently in development at https://localhost; the website is accessible but I am getting two critical errors:

I am not sure what could be causing this; could this be a caddy config issue ? How can I make sure wordpress can correctly loopback to itself with caddy ?

I have tried different solutions including adding “additional host on docker” like below but nothing seems to be working; I also made sure my hosts file has the correct loopback.

    extra_hosts:
      - localhost:127.0.0.1

here is my error message

The REST API encountered an error
Performance
The REST API is one way that WordPress and other applications communicate with the server. For example, the block editor screen relies on the REST API to display and save your posts and pages.

When testing the REST API, an error was encountered:

REST API Endpoint: https://localhost/wp-json/wp/v2/types/post?context=edit
REST API Response: (http_request_failed) cURL error 7: Failed to connect to localhost port 443 after 0 ms: Couldn't connect to server

and

Your site could not complete a loopback request
Performance
Loopback requests are used to run scheduled events, and are also used by the built-in editors for themes and plugins to verify code stability.

The loopback request to your site failed, this means features relying on them are not currently working as expected.
Error: cURL error 7: Failed to connect to localhost port 443 after 0 ms: Couldn't connect to server (http_request_failed)

I am not sure if this will solve by itself in prod

here is my compose file; DOMAIN_URL=https://localhost :

services:
  # Database
  db:
    image: mysql:8.0
    container_name: db
    platform: linux/arm64/v8
    volumes:
      - ${DATABASE_HOST}:/var/lib/mysql
      - "/etc/localtime:/etc/localtime:ro"
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    networks:
      - meoc

  # WordPress
  wordpress:
    depends_on:
      - db
    container_name: wordpress
    build:
      context: .
      dockerfile: Dockerfile.wordpress
    platform: linux/arm64/v8
    expose:
      - "80"
    restart: always
    volumes:
      - "/etc/localtime:/etc/localtime:ro"
      - ./settings/php/custom.ini:/usr/local/etc/php/conf.d/custom.ini
      - ./wp-content:/var/www/html/wp-content
    environment:
      WORDPRESS_DB_HOST: ${MYSQL_HOST}
      WORDPRESS_DB_USER: ${MYSQL_USER}
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_HOME', '${DOMAIN_URL}');
        define('WP_SITEURL', '${DOMAIN_URL}');
        define('FORCE_SSL_ADMIN', true);
        define('WP_CONTENT_URL', '${DOMAIN_URL}/wp-content');
        define('WORDPRESS_SKIP_PLUGINS', true);
        define('WORDPRESS_SKIP_THEMES', true);
    networks:
      - meoc

  # Caddy
  caddy:
    image: caddy:2-alpine
    container_name: caddy
    platform: linux/arm64/v8
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ${CADDY_FILE}:/etc/caddy/Caddyfile:ro
      - ${CADDY_DATA}:/data
      - ${CADDY_CONFIG}:/config
      - ${CADDY_LOG}:/var/log/caddy
    environment:
      - DOMAIN_URL=${DOMAIN_URL}
      - ACME_AGREE=true
    restart: always
    networks:
      - meoc

networks:
  eoc:
    name: meoc

and my caddyfile

# Global options
{
    admin off
    servers {
        protocols h1 h2
    }
}

localhost {
    tls internal
    log {
        output file /var/log/caddy/access.log {
			roll_size 1gb
			roll_keep 5
			roll_keep_for 720h
		}
        format filter {
			request>headers>Cookie cookie {
				replace session REDACTED
				delete secret
			}
		}
        format json
    }

    reverse_proxy wordpress:80 {
        header_up Host {host}
        header_up X-Real-IP {remote}
    }

    # Security headers
    header {
        # Enable HSTS
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        # Prevent MIME type sniffing
        X-Content-Type-Options "nosniff"
        # Prevent clickjacking
        X-Frame-Options "SAMEORIGIN"
        # Enable XSS protection
        X-XSS-Protection "1; mode=block"
        # Remove server header
        -Server
        # Disable caching
        Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"
        Pragma "no-cache"
        Expires "0"
    }
} 

This error happens because the localhost seen from the container running PHP dies not run a webserver, your WordPress settings assume both are run on the same network stack

ok but the problem seems to solve itself in production using TLS but is there a solution to localhost dev environment ? Why would it work in prod and not in dev ? I have the same settings in prod; only the domain name changed and not using tls internal

How does your production docker file look like?

services:
  # Database
  db:
    image: mysql:8.0
    container_name: db
    platform: ${PLATFORM}
    volumes:
      - ${DATABASE_HOST}:/var/lib/mysql
      - "/etc/localtime:/etc/localtime:ro"
      - ./settings/db/init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    networks:
      - meoc

  # WordPress
  wordpress:
    depends_on:
      - db
    container_name: wordpress
    build:
      context: .
      dockerfile: Dockerfile.wordpress
    platform: ${PLATFORM}
    expose:
      - "80"
      - "443"
    restart: always
    volumes:
      - "/etc/localtime:/etc/localtime:ro"
      - ./settings/php/custom.ini:/usr/local/etc/php/conf.d/custom.ini
      - ${WP_CONTENT}:/var/www/html/wp-content
      # - ${WP_CONFIG}:/var/www/html/wp-config.php
    environment:
      WORDPRESS_DB_HOST: ${MYSQL_HOST}
      WORDPRESS_DB_USER: ${MYSQL_USER}
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_HOME', '${DOMAIN_URL}');
        define('WP_HOST', '${DOMAIN_URL}');
        define('WP_SITEURL', '${DOMAIN_URL}');
        define('FORCE_SSL_ADMIN', true);
        define('WP_CONTENT_URL', '${DOMAIN_URL}/wp-content');
        define('WORDPRESS_SKIP_PLUGINS', true);
        define('WORDPRESS_SKIP_THEMES', true);
    networks:
      - meoc

  # Caddy
  caddy:
    image: caddy:2-alpine
    depends_on:
      - db
      - wordpress
    container_name: caddy
    platform: ${PLATFORM}
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ${CADDY_FILE}:/etc/caddy/Caddyfile:ro
      - ${CADDY_DATA}:/data
      - ${CADDY_CONFIG}:/config
      - ${CADDY_LOG}:/var/log/caddy
      - "/etc/localtime:/etc/localtime:ro"
    environment:
      - DOMAIN_BASE=${DOMAIN_BASE}
      - DOMAIN_LOOPBACK=${DOMAIN_LOOPBACK}
      - DOMAIN_URL=${DOMAIN_URL}
      - DOMAIN_EMAIL=${DOMAIN_EMAIL}
      - TLS_MODE=${TLS_MODE}
      - ACME_AGREE=true
    restart: always
    networks:
      - meoc
      
networks:
  eoc:
    name: meoc