Caddy redirecting to port :0

Hi everyone, I am having a little issue with caddy redirecting to port :0

1. Caddy version (caddy version):

Docker image caddy/caddy:latest (2.5.1)

2. How I run Caddy:

Running through docker/docker-compose in order to serve a Grav CMS (PHP) website.

a. System environment:

docker/docker-compose

b. Command:

docker-compose up -d

c. Service/unit/compose file:

version: '3.9'

services:
  caddy:
    image: caddy/caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./:/var/www/grav

  php:
    build:
      context: .
    restart: unless-stopped

d. My complete Caddyfile or JSON config:

localhost {
    root * /var/www/grav
    encode gzip
    php_fastcgi php:9000
    file_server
    log stdout

    # Begin - Security
    # deny all direct access for these folders
    rewrite /(\.git|cache|bin|logs|backups|tests)/.* /403

    # deny running scripts inside core system folders
    rewrite /(system|vendor)/.*\.(txt|xml|md|html|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ /403

    # deny running scripts inside user folder
    rewrite /user/.*\.(txt|md|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ /403

    # deny access to specific files in the root folder
    rewrite /(LICENSE\.txt|composer\.lock|composer\.json|nginx\.conf|web\.config|htaccess\.txt|\.htaccess) /403

    respond /403 403
    ## End - Security

    # global rewrite should come last.
    # try_files {path} {path}/ /index.php?_url={uri}&{query}
}

3. The problem I’m having:

I am able to serve the website, however, links to other pages have a :0 port added upon receiving the response.
Caddy seems to be redirecting to the port :0 as the status code is 302.

4. Error messages and/or full log output:

{"level":"info","ts":1655740153.5991714,"logger":"http.log.access","msg":"handled request","request":{"method":"GET","uri":"/fr/","proto":"HTTP/2.0","remote_addr":"172.18.0.1:53778","host":"localhost","headers":{"Sec-Fetch-User":["?1"],"Referer":["https://localhost/"],"Accept-Language":["en-GB,en;q=0.9,en-US;q=0.8,fr;q=0.7"],"Accept-Encoding":["gzip, deflate, br"],"Cache-Control":["no-cache"],"Sec-Ch-Ua":["\"Chromium\";v=\"104\", \"/Not)A;Brand\";v=\"24\", \"Microsoft Edge\";v=\"104\""],"Sec-Ch-Ua-Mobile":["?0"],"Sec-Ch-Ua-Platform":["\"Linux\""],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-Dest":["document"],"Pragma":["no-cache"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5070.0 Safari/537.36 Edg/104.0.1271.2"],"Cookie":["_ga=GA1.1.177098245.1631335347; __atuvc=4%7C16; _ga_ECXM5C73YV=GS1.1.1653553530.1.1.1653554489.0; grav-site-b3974d7=bd58c71703a10ec4c76df1c04e63089a"],"Upgrade-Insecure-Requests":["1"],"Sec-Fetch-Site":["same-origin"]},"tls":{"resumed":false,"version":772,"ciphersuite":4865,"proto":"h2","proto_mutual":true,"server_name":"localhost"}},"common_log":"172.18.0.1 - - [20/Jun/2022:15:49:13 +0000] \"GET /fr/ HTTP/2.0\" 302 0","latency":0.073750452,"size":0,"status":302,"resp_headers":{"Status":["302 Found"],"X-Powered-By":["PHP/7.3.18"],"Expires":["Thu, 19 Nov 1981 08:52:00 GMT"],"Cache-Control":["no-store, no-cache, must-revalidate"],"Location":["https://localhost:0/fr"],"Server":["Caddy"],"Content-Type":["text/html; charset=UTF-8"],"Pragma":["no-cache"],"Set-Cookie":["grav-site-b3974d7=bd58c71703a10ec4c76df1c04e63089a; expires=Mon, 20-Jun-2022 16:19:13 GMT; Max-Age=1800; path=/; secure; HttpOnly; SameSite=Lax"]}}
curl -v http://localhost/fr
*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /fr HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://localhost/fr
< Server: Caddy
< Date: Mon, 20 Jun 2022 15:52:54 GMT
< Content-Length: 0
< 
* Closing connection 0

5. What I already tried:

I tried to disable HTTPS but got the same result.

Does that happen if you remove php_fastcgi from your config?

The pages and links are provided by PHP, do you mean to serve a static html page with links, to test the behaviour?

Yeah. Is the redirect originating from Caddy or the PHP app? Removing php_fastcgi will help us be sure.

That’s Caddy’s HTTP->HTTPS redirect. You made your curl -v request with http://. Please make a request to https:// and show us what that looks like.

1 Like

I tested and caddy seems to work as expected.
I tested on different browsers and have different behaviours:
On Edge it adds :0

On both Chrome and Firefox, it does not follow the link, it stays on the page.
However looking at the network tab I have the following:

Cache-Control
	no-store, no-cache, must-revalidate
Content-Length
	0
Content-Type
	text/html; charset=UTF-8
Date
	Wed, 22 Jun 2022 05:33:49 GMT
Expires
	Thu, 19 Nov 1981 08:52:00 GMT
Location
	http://localhost:0/fr
Pragma
	no-cache
Server
	Caddy
	grav-site-b3974d7=a4d6a41756c0756ad8977902b570dab5; expires=Wed, 22-Jun-2022 06:03:49 GMT; Max-Age=1800; path=/; HttpOnly; SameSite=Lax
Status
	302 Found
X-Powered-By
	PHP/7.3.18
Set-Cookie
	grav-site-b3974d7=a4d6a41756c0756ad8977902b570dab5; expires=Wed, 22-Jun-2022 06:03:49 GMT; Max-Age=1800; path=/; HttpOnly; SameSite=Lax
Status
	302 Found
X-Powered-By
	PHP/7.3.18

It must be originating from PHP then, however I am not encountering the issue when using PHP’s built-in Web Server.

Yes, sorry I had captured the output when I was testing with HTTPS.
Even entirely disabling HTTPS redirection I have the same problem,
curl -v http://localhost returns the following:

*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /fr HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Methods: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
< Access-Control-Allow-Origin: *
< Cache-Control: max-age=604800
< Content-Type: text/html;charset=UTF-8
< Etag: "4d5974822389871b455cd7970af3091f"
< Expires: Wed, 29 Jun 2022 05:22:35 GMT
< Pragma: no-cache
< Server: Caddy
< Set-Cookie: grav-site-b3974d7=0d04a1badc3c66669e41612339674b15; expires=Wed, 22-Jun-2022 05:52:35 GMT; Max-Age=1800; path=/; HttpOnly; SameSite=Lax
< X-Powered-By: PHP/7.3.18
< Date: Wed, 22 Jun 2022 05:22:35 GMT
< Transfer-Encoding: chunked

Seems like a configuration issue with your upstream app. Make sure it has a port configured so that it doesn’t try to redirect with a zero port.

1 Like

It seems to be a problem with the combination of Grav and Caddy.
I cannot replicate the problem with Apache or NGINX, only caddy makes PHP behave this way.
Both Apache and NGINX make PHP send the location of the redirects as localhost/* whereas
Caddy makes PHP indicate localhost:0/

I just noticed something…

caddy/caddy:latest isn’t actually v2.5.1 but instead v2.0.0-rc.3 :thinking:
You can test that yourself with

❯ docker run -it --rm caddy/caddy:latest caddy version
v2.0.0-rc.3 h1:z2H/QnaRscip6aZJxwTbghu3zhC88Vo8l/K57WUce4Q=

Please use caddy:latest instead of caddy/caddy:latest

❯ docker run -it --rm caddy:latest caddy version
v2.5.1 h1:bAWwslD1jNeCzDa+jDCNwb8M3UJ2tPa8UZFFzPVmGKs=

There was fastcgi: Comply with RFC3875, ensure a leading slash on index rewrite by francislavoie · Pull Request #3570 · caddyserver/caddy · GitHub merged in v2.2.0, which might just fix your problem, though I didn’t look at grav’s source code that closely :sweat_smile:

Before that, caddy wrongly passed SERVER_PORT="" (empty string) for the php_fastcgi directive instead of omitting it. The very var, grav just converts down to an integer if set (0 for an empty string).


If your problem persists, would you mind sharing the Dockerfile for your php container and some (perhaps stripped) grav config?

2 Likes