Can't figure out how to bind to just 0.0.0.0:8087 rather than localhost

1. Caddy version (caddy version):

xcaddy build v2.4.6 --with github.com/baldinof/caddy-supervisor

2. How I run Caddy:

Caddyfile and caddy run inside a podman container

a. System environment:

MacOS 12.3 Monterey

Running a container with podman using podman run -it --rm -p 127.0.0.1:8097:8097 --network slirp4netns

b. Command:

caddy run

c. Service/unit/compose file:

FROM caddy:2.4.6-builder AS caddybuilder

RUN xcaddy build \
    --with github.com/baldinof/caddy-supervisor

FROM caddy:2.4.6

RUN apk add --update sudo

RUN adduser -D portal \
    && echo "portal ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/portal \
    && chmod 0440 /etc/sudoers.d/portal

ARG application_env
ARG memcache_save_path

ENV APPLICATION_ENV=$application_env
ENV MEMCACHED_SESSION_STORAGE_SAVE_PATH=$memcache_save_path

run apk --no-cache add git openssh-client

# https://github.com/nunomaduro/phpinsights/issues/43#issuecomment-917389852
RUN apk --no-cache add php7-mbstring php7-iconv

RUN apk --no-cache add php7-fpm php7-phar php7-json php7-openssl php7-simplexml php7-pdo

COPY --from=caddybuilder /usr/bin/caddy /usr/bin/caddy
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

ADD webserver /project/webserver
WORKDIR /project/webserver
RUN composer install --no-dev --optimize-autoloader --no-scripts --no-plugins --prefer-dist --no-interaction

ADD tools/runtime_config /project/runtime_config
run mkdir /project/runtime /project/logs
WORKDIR /project/runtime_config

run chown portal /project/runtime /project/logs
USER portal

CMD ["/usr/bin/env", "caddy", "run"]

d. My complete Caddyfile or JSON config:

{
    admin off
    auto_https off

    supervisor {
        ./php-fpm -p . -c . -y fpm.conf -F {
            redirect_stdout stdout
            redirect_stderr stderr
        }
    }
}

:8087 {
    @trailing-slash {
        path_regexp dir (.+)/$
    }

    @not-trailing-slash {
        path_regexp dir (.+)[^/]$
    }

    root * ../../webserver/portal

    php_fastcgi unix/../runtime/fpm.sock {
        try_files @trailing-slash {re.dir.1}.php {re.dir.1}/index.php
        try_files @not-trailing-slash {path}.php {path}/index.php =404
    }

    log

    encode zstd gzip

    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /not-found.php
        reverse_proxy @404 unix/../runtime/fpm.sock {
            transport fastcgi {
                split .php
            }
        }
    }
}

3. The problem I’m having:

It appears caddy binds to localhost in the podman container and so when I curl from the host I get refused

I can’t work out how to make it so that caddy binds to 0.0.0.0:8087 and nothing else. In dev use I’ll use this outside of podman locally but I’m trying to test it on my mac before I push it up to google cloud run and not being able to reach it from outside is frustrating.

5. What I already tried:

if I try

0.0.0.0:8087 {
   ...
}

Then caddy complains

2022/04/04 05:30:44 [WARNING] Site block has unspecified IP address 0.0.0.0 which only matches requests having that Host header; you probably want the 'bind' directive to configure the socket

and curl continues to be refused from the host

so I try

bind 0.0.0.0:8087 {
   ...
}

but then

run: loading initial config: loading new config: http app module: start: tcp: listening on :443: listen tcp :443: bind: permission denied

and I don’t know how to tell caddy I don’t want it to use 443.

That seems like a bad idea. Set an absolute root instead:

root * /project/webserver/portal

You can’t use request matchers inside of directives, for their subdirectives. Only the last try_files subdirective will take (the first one will be completely discarded), and it will try to look for a file literally called @not-trailing-slash on disk, first (which will never be found, obviously, wasting a system call).

I don’t quite understand what you’re trying to do here, so I’m not sure what to suggest instead, but that’s definitely not right.

That’s definitely not true. Caddy’s default bind is 0.0.0.0, i.e. all interfaces.

Yep, Caddy complaining here is correct, because this is the site address, which in the Caddyfile, the port maps to the listener and the hostname maps to a host matcher. A host matcher of 0.0.0.0 doesn’t make sense.

bind is a directive, it’s not a prefix that you can use as a site address or w/e.

Either way, you don’t need bind in your case, I think you’re just misunderstanding the problem.

Try curl -v http://127.0.0.1:8087. If that does work, then the issue is that curl is trying to connect to ::1 i.e. IPv6 localhost by default (because your /etc/hosts has localhost mapping to ::1), but since your Docker port mapping is limited to 127.0.0.1, IPv6 doesn’t work.

Try removing 127.0.0.1 from the -p when your run your container.

That seems like a bad idea. Set an absolute root instead:

I can do that in the container, but I use this locally too and in that case I don’t necessarily know where the project is located and the Caddyfile is in a directory next to where the php is

You can’t use request matchers inside of directives, for their subdirectives. Only the last try_files subdirective will take (the first one will be completely discarded), and it will try to look for a file literally called @not-trailing-slash on disk, first (which will never be found, obviously, wasting a system call).

It actually works though hahaha

old thing that means it’s possible to go /logout/ on some paths which I want to be logout.php but without that first try_files it doesn’t work. But if I have it then it does.

So the matcher @trailing-slash matches when the path ends with slash and for that it’ll try it as if it’s actually a file rather than a dictionary and then treat it like it’s a directory and look for an index.php

Then without the slash it seems if it’s a php or is a directory with an index.php

I don’t quite understand what you’re trying to do here, so I’m not sure what to suggest instead, but that’s definitely not right.

taming a beast lol :stuck_out_tongue: (and migrating from apache)

Try curl -v http://127.0.0.1:8087. If that does work, then the issue is that curl is trying to connect to ::1 i.e. IPv6 localhost by default (because your /etc/hosts has localhost mapping to ::1), but since your Docker port mapping is limited to 127.0.0.1, IPv6 doesn’t work.

Try removing 127.0.0.1 from the -p when your run your container.

same results

Though perhaps you’re correct about 0.0.0.0 and I misread this netstat output? and probs more an issue with podman and mac?

also if those try_files aren’t inside the php_fastcgi block then they don’t seem to work at all

though it’s entirely possible what I thought was working with the try_files was actually broken behaviour.

Gonna try

    @maybe-slash {
        path_regexp dir (.+)/?$
    }

    try_files @maybe-slash {re.dir.1}.php {re.dir.1}/index.php =404

instead

either way, an irrelevant issue to the thread :slight_smile:

If so, only by accident.

Look at the output of caddy adapt, look at the JSON. You’ll notice that it makes no sense, and doesn’t match what you were trying to do.

That’s really strange :thinking: why would you have URLs like that in your app? Don’t use a trailing slash unless you actually mean to index. Your app is using incorrect URL semantics if it’s doing this. I think you should just fix your app, don’t try to make Caddy bend backwards to accommodate.

No, like I said, the matcher literally never runs.

That looks correct. I’m not sure what you’re trying to point at? Caddy is listening on all interfaces. The key is how you’re mapping that to your host machine.

The try_files directive (i.e. not inside php_fastcgi, different thing altogether) doesn’t support matchers either, because it’s actually just a shortcut for a file matcher and a rewrite. See the docs:

If you really can’t fix the URLs in your app, then I suggest making more targeted rewrite instead of playing with try_files.

1 Like

why would you have URLs like that in your app?

inherited 20 year old php, probably easy to fix the logout one ,but not necessarily easy to find where else it does stupid things like that.

Look at the output of caddy adapt

ooh, that’s a nice command

See the docs:

Not gonna lie, Caddy docs are confusing. I’ve read all these things so many times and they’re a bit too disconnected and confusing

If you really can’t fix the URLs in your app, then I suggest making more targeted rewrite instead of playing with try_files .

Yeah, started going down that path just now.

doesn’t help when you see suggestions that then don’t work, which I assume is because caddy1 is different to caddy2 and the internet isn’t great for when that kind of update happens.

for example

    rewrite {
        if {path} not /
        if {path} ends_with /
        r ^/(.*)/$
        to /{1}
    }
run: adapting config using caddyfile: parsing caddyfile tokens for 'rewrite': Caddyfile:14 - Error during parsing: Wrong argument count or unexpected line ending after 'rewrite'

If I can rewrite to remove the trailing slash then I think php_fastcgi should do the right thing yeah?

this seems to work

    @trailing-slash {
        path_regexp dir (.+)/$
    }
    rewrite @trailing-slash {re.dir.1}

    root * ../../webserver/portal

    try_files {path} {path}.php {path}/index.php =404
    php_fastcgi unix/../../runtime/fpm.sock

Now hopefully the port works when I put this in cloud run and I can just give up on podman and mac working for me as maybe that has similar problems to docker on mac where such things are just broken

Yes. Read the docs, don’t use Google.

Or search the forums (with Google) and only look at results from the past year or two.

And if you haven’t already, the Caddyfile Concepts page is essentially required reading:

Yes. Read the docs, don’t use Google.

I certainly do use the docs first

And if you haven’t already, the Caddyfile Concepts page is essentially required reading:

will read, thanks.

when I put this in cloud run

Just remembered the port google cloud run looks at is set as an environment variable.

is it possible to tell the Caddyfile to use a port defined in an environment variable?
edit: apparently you can tell google cloud run to use a particular port

I ended up with this in the end

Caddy built with modules

xcaddy build v2.4.6 --with github.com/baldinof/caddy-supervisor --with github.com/leodido/caddy-jsonselect-encoder

Caddyfile

{
	admin off
	auto_https off
	supervisor {
		./php-fpm -p . -c . -y fpm.conf -F {
			redirect_stdout stdout
			redirect_stderr stderr
		}
	}

	log {
		format json {
			level_key "severity"
			level_format "upper"
			time_format "rfc3339_nano"
		}
	}
}

:8087 {
	@trailing-slash {
		path_regexp dir (.+)/$
	}
	rewrite @trailing-slash {re.dir.1}

	root * ../../webserver/portal

	try_files {path} {path}.php {path}/index.php =404
	php_fastcgi unix/../../runtime/fpm.sock {
		# php-fpm takes a few seconds the first time
		lb_try_duration 5s
	}

	log {
		format jsonselect "{severity:level} {timestamp:ts} {logName:logger} {httpRequest>requestMethod:request>method} {httpRequest>protocol:request>proto} {httpRequest>status:status} {httpRequest>responseSize:size} {httpRequest>userAgent:request>headers>User-Agent>[0]} {httpRequest>requestUrl:request>uri}" "{httpRequest>referrer:request>headers>Referer>[0]}" {
			level_format "upper"
			time_format "rfc3339_nano"
		}
	}

	encode zstd gzip

	handle_errors {
		@404 {
			expression {http.error.status_code} == 404
		}
		rewrite @404 /not-found.php
		reverse_proxy @404 unix/../../runtime/fpm.sock {
			transport fastcgi {
				split .php
			}
		}
	}
}

fpm.conf

[global]
pid = ../../runtime/php-fpm.pid

error_log = ../../runtime/php-fpm.log

daemonize = no

[www]
listen = "../../runtime/fpm.sock"
clear_env = no
pm = static
pm.max_children = 20

php.ini

variables_order = "EGPCS"

session.save_handler = ${MEMCACHED_SESSION_STORAGE_SAVE_HANDLER}
session.save_path = ${MEMCACHED_SESSION_STORAGE_SAVE_PATH}

opcache.enable = ${OPCACHE_ENABLE}
opcache.memory_consumption=128
opcache.interned_strings_buffer=64
opcache.max_accelerated_files=32531
opcache.validate_timestamps=0
opcache.save_comments=1
opcache.fast_shutdown=0

Containerfile

FROM caddy:2.4.6-builder AS caddybuilder

RUN xcaddy build \
    --with github.com/baldinof/caddy-supervisor \
    --with github.com/leodido/caddy-jsonselect-encoder

FROM caddy:2.4.6

RUN apk add --update sudo

RUN adduser -D portal \
    && echo "portal ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/portal \
    && chmod 0440 /etc/sudoers.d/portal

run apk --no-cache add git openssh-client

# https://github.com/nunomaduro/phpinsights/issues/43#issuecomment-917389852
RUN apk --no-cache add php7-mbstring php7-iconv

RUN apk --no-cache add php7-memcached php7-session php7-fpm php7-bcmath php7-phar php7-json php7-openssl php7-simplexml php7-pdo

COPY --from=caddybuilder /usr/bin/caddy /usr/bin/caddy
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

ADD webserver/composer.json /project/webserver/composer.json
ADD webserver/composer.lock /project/webserver/composer.lock
WORKDIR /project/webserver
RUN composer install --no-dev --optimize-autoloader --no-scripts --no-plugins --prefer-dist --no-interaction

ADD config /project/config
ADD webserver/app /project/webserver/app
ADD webserver/portal /project/webserver/portal

ADD tools/runtime_config /project/tools/runtime_config
run mkdir /project/runtime /project/logs /assets-manifest-cache
WORKDIR /project/tools/runtime_config

run chown portal /project/runtime /project/logs /assets-manifest-cache
USER portal

CMD ["/usr/bin/env", "caddy", "run"]

And it seems to work quite well. Super can’t wait till caddy 2.5.0 comes out and I can add the tracing directive too !

Thanks for your help and patience @francislavoie !

I’ll give up on the original question around podman and Mac, I get this feeling that’s just not solvable and not much more than a nice to have than anything :stuck_out_tongue:

1 Like

You can use v2.5.0-beta.1 right now. It’s pretty stable, no major bugs.

You can use v2.5.0-beta.1 right now. It’s pretty stable, no major bugs.

oooooh nice. Unfortunately I don’t think I’ll get buy-in for using something with beta in it’s version for this particular project heheheh

This topic was automatically closed after 30 days. New replies are no longer allowed.