lucaslorentz / caddy-docker-proxy

Caddy as a reverse proxy for Docker
MIT License
2.85k stars 168 forks source link

multiline directives seems not to work #168

Closed torwag closed 4 years ago

torwag commented 4 years ago

Using caddy2 by utilizing docker

    image: lucaslorentz/caddy-docker-proxy:latest
    container_name: caddy
    restart: unless-stopped
    command: docker-proxy  -caddyfile-path=/config/Caddyfile
    networks:
      proxy:
    ports:
      - "80:80"
      - "443:443"
    environment:
      - MY_DOMAIN=$MYDOMAIN
    volumes:
      - caddy_data/:/data
      - caddy_config/:/config
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - caddy.email=$MYMAIL

I tried to get most caddy configuration in the individual docker-compose files. For nextcloud I should add some header information. I tried (note the two differnt way to add escape a quote by using escape and double quotes and single escape quotes :

    labels:
      caddy: nc.MYDOMAIN nextcloud.MYDOMAIN
      caddy.header: "/"
      caddy.header.Strict-Transport-Security: "\"max-age=15552000;\""
      caddy.header.Referrer-Policy: "strict-origin-when-cross-origin"
      caddy.header.X-XSS-Protection: \"1; mode=block\"
      caddy.header.X-Content-Type-Options: "nosniff"
      caddy.header.X-Frame-Options: "SAMEORIGIN"
      caddy.reverse_proxy: "{{upstreams 80}}"

Actually I tried many forms with and without quotes, with escaped quotes, etc. But nothing seems to work correctly. I always checked in the caddy logs, how it was parsed. E.g. the above example was interpreted as

nc.MYDOMAIN nextcloud.MYDOMAIN {
       header / {
                 Referrer-Policy strict-origin-when-cross-origin
                 Strict-Transport-Security "\"max-age=15552000;\""
                 X-Content-Type-Options nosniff
                 X-Frame-Options SAMEORIGIN
                 X-XSS-Protection "\"1;" "mode=block\""
             }
}

As you can see, there are those funny double quotes now, were I expect that one quote should be gone, like in the single quote cases.

However, not escaping those quotes, they are removed completely:

header / {
     Referrer-Policy strict-origin-when-cross-origin
     Strict-Transport-Security max-age=15552000;
     X-Content-Type-Options nosniff
     X-Frame-Options SAMEORIGIN
     X-XSS-Protection 1; mode=block
}

Thus, I am a bit puzzled how to get a single set of quotes

francislavoie commented 4 years ago

Out of curiosity, where did you get that config example? It's incorrect, there should not be a / as a path matcher, that will only make it apply for requests to / and not /foo as Caddy v2 path mathcing is exact-match. I keep seeing people use that config but I don't know where they're getting it from.

Since Caddy v2.1, you can use backticks as well as double quotes for strings (see https://caddyserver.com/docs/caddyfile/concepts#tokens-and-quotes). That means you can do this (also remove the / matcher by setting an empty argument):

    labels:
      caddy: nc.MYDOMAIN nextcloud.MYDOMAIN
      caddy.header: ""
      caddy.header.Strict-Transport-Security: "`max-age=15552000;`"
      caddy.header.Referrer-Policy: "strict-origin-when-cross-origin"
      caddy.header.X-XSS-Protection: "`1; mode=block`"
      caddy.header.X-Content-Type-Options: "nosniff"
      caddy.header.X-Frame-Options: "SAMEORIGIN"
      caddy.reverse_proxy: "{{upstreams 80}}"

That said I guess it could be considered a bug that escaping double quotes doesn't work at the label level? 🤔 @lucaslorentz

With the way that Caddy parses tokens, whitespace is very significant. If you don't use quotes, then it'll try to read each segment separated by whitespace as separate tokens, i.e. multiple arguments to a directive instead of a single argument that contains whitespace (by using quotes or backticks). Since labels are being set using yaml which also has its own double quote support, it gets tricky since it's layered parsing.

torwag commented 4 years ago

Thanks for the quick answer, It is coming from here example nextcloud I guess a lot of confusion comes from the fact that many documentation does not yet clarify if it works for "old" caddy 1, "new" caddy 2, or working for both... I give your backticks a try. Thanks

torwag commented 4 years ago

It seems to get a bit better but still does not work. Interesting observation... caddy.header.Strict-Transport-Security: "`max-age=15552000;`" will end up to be (according to caddy log)


           Strict-Transport-Security: max-age=15552000;
        }```
whereas 
```caddy.header.Strict-Transport-Security: "`max-age = 15552000;`"```
note the blanks between the equal sign ends up to be:
      ```header {
           Strict-Transport-Security: "max-age = 15552000;"
        }```
That seems to be true for all directives.... using backsticks results in no space  = no quote and spaces = quotes
francislavoie commented 4 years ago

It is coming from here example nextcloud I guess a lot of confusion comes from the fact that many documentation does not yet clarify if it works for "old" caddy 1, "new" caddy 2, or working for both...

It's clearly marked on that repo that those are v1 examples, and the repo is archived. Caddy v2 is a complete rewrite and I wish people wouldn't assume there exists compatibility between the two. Any similarities are due to design decisions from v1 that were deemed good and therefore kept similar in v2. The upgrade guide covers that all pretty clearly.

lucaslorentz commented 4 years ago

There is indeed a bug when parsing label. This function: https://github.com/lucaslorentz/caddy-docker-proxy/blob/master/plugin/caddyfile/fromlabels.go#L78 Should interpret the quoted text as a single arg, removing quotes. Maybe I can use the caddyfile tokenizer there as well, so the same rules will be applied.

francislavoie commented 4 years ago

The new Tokenize function isn't in a tagged release yet @lucaslorentz :thinking:

lucaslorentz commented 4 years ago

I copied the lexer some time ago, I will try to use it

lucaslorentz commented 4 years ago

@torwag I merged a fix for that. Can you please test it using the lastest CI images?

image: lucaslorentz/caddy-docker-proxy:ci

Please follow the README instructions. It starts with If you need whitespace or line-breaks inside one of the arguments...

Let us know if it behaves as expected.

lucaslorentz commented 4 years ago

Released: https://github.com/lucaslorentz/caddy-docker-proxy/releases/tag/v2.3.0