Unable to run app in Docker at HTTPS with the Caddy as reverse proxy

1. The problem I’m having:

I have a server with Docker engine installed and trying to run R RStudio and R Shiny app in Docker at HTTPS with the help of Caddy as reverse proxy. I was able to successfully run these apps in containers at HTTP, but not HTTPS.
I have tried many configurations of docker-compose.yaml and Caddyfile files, but with no luck. Any help would be highly appreciated. Many thanks in advance.

2. Error messages and/or full log output:

I am getting repeated this error:

Caddy             | {"level":"info","ts":1702338636.512303,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy             | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first

In

3. Caddy version:

4. How I installed and ran Caddy:

I installed and ran Caddy via Docker, below is my docker-compose.yaml file

networks:
  caddy:

services:

  rstudio:
    image: rocker/verse:4
    container_name: rstudio
    ports:
      - "8787:8787"
    environment:
      PASSWORD: 123456
    networks:
      - caddy

ssh_test:
    image: rcepka/ssh_test
    container_name: roberts_ssh_test
    ports:
      - 3838:3838
    networks:
      - caddy

  caddy:
    image: caddy:latest
    restart: unless-stopped
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_config:/config
    networks:
      - caddy

volumes:
  caddy_data:
    external: true
  caddy_config:

a. System environment:

Ubuntu 22.04 with Docker version 24.0.7

b. Command:

I am running Caddy via Docker compose, so:
docker compose up

c. Service/unit/compose file:

d. My complete Caddy config:

{
  email myemail@myemail.com
}
real-estate.datageeks.sk {
  reverse_proxy rstudio:8787
}
real-estate.datageeks.sk {
  reverse_proxy ssh_test:3838
}

5. Links to relevant resources:

Are you sure that’s your entire config? That config wouldn’t produce that error message.

In fact, your config would produce this message:

Error: ambiguous site definition: real-estate.datageeks.sk

You have two site blocks with the same domain name; that’s invalid.

Hi @francislavoie,
many thanks for your response.

I was not sure about my config nor anything, because I spent tons of time on this trying many things.

So to avoid eventual misconfigurations I did the following:

1.) created a brand new virtual server with clean Ubuntu 22.04 and installed Docker on it

2.) created new subdomain test2.datageeks.sk and pointed it to the new server IP

3.) created this docker-compose.yaml file:

networks:
  caddy:

services:

  rstudio:
    image: rocker/verse:4
    container_name: rstudio
    ports:
      - "8787:8787"
    environment:
      PASSWORD: 123456
    networks:
      - caddy

  ssh_test:
    image: rcepka/ssh_test
    container_name: ssh_test
    ports:
      - "3838:3838"
    networks:
      - caddy


  caddy:
    image: caddy:latest
    restart: unless-stopped
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./containers/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
    networks:
      - caddy

volumes:
  caddy_data:
    external: true
  caddy_config:

4.) Created this Caddyfile:

{
debug
}
{
test2.datageeks.sk
        reverse_proxy ssh_test:3838
        reverse_proxy rstudio:8787
}

Note: I tried include only one, then another container and also both as above as reverse_proxy. Results described below were always the same.

4.) Then I ran docker compose up

Results:

  • all my target containers rstudio and also `ssh_test with corresponding apps ran successfully, but only at HTTP. HTTPS does not work.
  • I am getting these outputs in terminal:
[+] Running 3/0
 ✔ Container ssh_test  Created                                                                                                                                                                        0.0s
 ✔ Container caddy     Created                                                                                                                                                                        0.0s
 ✔ Container rstudio   Created                                                                                                                                                                        0.0s
Attaching to caddy, rstudio, ssh_test
rstudio   | [s6-init] making user provided files available at /var/run/s6/etc...exited 0.
rstudio   | [s6-init] ensuring user provided files have correct perms...exited 0.
rstudio   | [fix-attrs.d] applying ownership & permissions fixes...
rstudio   | [fix-attrs.d] done.
rstudio   | [cont-init.d] executing container initialization scripts...
rstudio   | [cont-init.d] 01_set_env: executing...
rstudio   | skipping /var/run/s6/container_environment/HOME
rstudio   | skipping /var/run/s6/container_environment/PASSWORD
rstudio   | skipping /var/run/s6/container_environment/RSTUDIO_VERSION
rstudio   | [cont-init.d] 01_set_env: exited 0.
rstudio   | [cont-init.d] 02_userconf: executing...
caddy     | {"level":"info","ts":1702388734.4616187,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
rstudio   | [cont-init.d] 02_userconf: exited 0.
rstudio   | [cont-init.d] done.
rstudio   | [services.d] starting services
rstudio   | [services.d] done.
ssh_test  |
ssh_test  | R version 4.3.1 (2023-06-16) -- "Beagle Scouts"
ssh_test  | Copyright (C) 2023 The R Foundation for Statistical Computing
ssh_test  | Platform: x86_64-pc-linux-gnu (64-bit)
ssh_test  |
ssh_test  | R is free software and comes with ABSOLUTELY NO WARRANTY.
ssh_test  | You are welcome to redistribute it under certain conditions.
ssh_test  | Type 'license()' or 'licence()' for distribution details.
ssh_test  |
ssh_test  |   Natural language support but running in an English locale
ssh_test  |
ssh_test  | R is a collaborative project with many contributors.
ssh_test  | Type 'contributors()' for more information and
ssh_test  | 'citation()' on how to cite R or R packages in publications.
ssh_test  |
ssh_test  | Type 'demo()' for some demos, 'help()' for on-line help, or
ssh_test  | 'help.start()' for an HTML browser interface to help.
ssh_test  | Type 'q()' to quit R.
ssh_test  |
ssh_test  | > shiny::runApp('/srv/shiny-server/app', host = '0.0.0.0', port = 3838)
caddy exited with code 0
caddy     | {"level":"info","ts":1702388735.778602,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
ssh_test  | Loading required package: shiny
ssh_test  |
ssh_test  | Listening on http://0.0.0.0:3838
caddy     | {"level":"info","ts":1702388736.8376973,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388737.7359161,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388739.022163,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388741.122802,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388744.7978094,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388751.6877663,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388764.993964,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1
caddy     | {"level":"info","ts":1702388791.1033099,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1

What went wrong please, do you see there any bug or mistake? I did not touch any other Caddy settings…

That’s invalid syntax. Your braces are not in the right places. Please review Caddyfile Concepts — Caddy Documentation which explains the structure.

Also, having two reverse_proxy in one site like that without any matchers will not work. It’s not possible to serve two apps from the same domain without splitting up the traffic somehow. So you’ll need to decide how you want to do that. I recommend using a subdomain for each service.

Thanks for pointing-out the syntax error. I also removed the second reverse_proxy line. Now my Caddifile is really simple, it looks like this:

test2.datageeks.sk {
        reverse_proxy ssh_test:3838
}

{
 debug
}

But still no joy, HTTP works but HTTPS does not.
I am getting this error:

caddy     | {"level":"info","ts":1702401325.7383597,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
caddy exited with code 1

What does it mean please?

The error message is accurate.

You must place global options first in your Caddyfile, before any sites.

Move this to the top:

{
	debug
}

Stupid mistake, thank you, I am starting to get used to the terminology.

I did the entire process again, new clean server & Docker install, two test subdomains are pointed to server: “test” and “test2”.

My Caddyfile looks like this:

{
 debug
}

test.datageeks.sk {
        reverse_proxy ssh_test:3838
}

test2.datageeks.sk {
        reverse_proxy rstudio:8787
}

Docker compose file hasnt changed.

The result as before, HTTP works for both apps, HTTPS does not.

Here are also logs:

 ✔ Container caddy     Created                                                                                                                                  0.0s
 ✔ Container rstudio   Created                                                                                                                                  0.0s
 ✔ Container ssh_test  Created                                                                                                                                  0.0s
Attaching to caddy, rstudio, ssh_test
rstudio   | [s6-init] making user provided files available at /var/run/s6/etc...exited 0.
ssh_test  |
ssh_test  | R version 4.3.1 (2023-06-16) -- "Beagle Scouts"
ssh_test  | Copyright (C) 2023 The R Foundation for Statistical Computing
ssh_test  | Platform: x86_64-pc-linux-gnu (64-bit)
ssh_test  |
ssh_test  | R is free software and comes with ABSOLUTELY NO WARRANTY.
ssh_test  | You are welcome to redistribute it under certain conditions.
ssh_test  | Type 'license()' or 'licence()' for distribution details.
ssh_test  |
ssh_test  |   Natural language support but running in an English locale
ssh_test  |
ssh_test  | R is a collaborative project with many contributors.
ssh_test  | Type 'contributors()' for more information and
ssh_test  | 'citation()' on how to cite R or R packages in publications.
ssh_test  |
ssh_test  | Type 'demo()' for some demos, 'help()' for on-line help, or
ssh_test  | 'help.start()' for an HTML browser interface to help.
ssh_test  | Type 'q()' to quit R.
ssh_test  |
rstudio   | [s6-init] ensuring user provided files have correct perms...exited 0.
rstudio   | [fix-attrs.d] applying ownership & permissions fixes...
rstudio   | [fix-attrs.d] done.
rstudio   | [cont-init.d] executing container initialization scripts...
rstudio   | [cont-init.d] 01_set_env: executing...
caddy     | {"level":"info","ts":1702425732.0844746,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy     | {"level":"warn","ts":1702425732.088941,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
caddy     | {"level":"info","ts":1702425732.0914838,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
caddy     | {"level":"info","ts":1702425732.0920043,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
caddy     | {"level":"info","ts":1702425732.092472,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
caddy     | {"level":"debug","ts":1702425732.0928676,"logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{}]}},"http":{"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"rstudio:8787"}]}]}]}],"terminal":true},{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"ssh_test:3838"}]}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}}}}}
caddy     | {"level":"info","ts":1702425732.100817,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
caddy     | {"level":"info","ts":1702425732.105592,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
caddy     | {"level":"debug","ts":1702425732.10619,"logger":"http","msg":"starting server loop","address":"[::]:443","tls":true,"http3":true}
caddy     | {"level":"info","ts":1702425732.1065016,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
caddy     | {"level":"debug","ts":1702425732.106818,"logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}
caddy     | {"level":"info","ts":1702425732.1070864,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
caddy     | {"level":"info","ts":1702425732.107362,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["test2.datageeks.sk","test.datageeks.sk"]}
caddy     | {"level":"debug","ts":1702425732.1081786,"logger":"tls","msg":"loading managed certificate","domain":"test2.datageeks.sk","expiration":1710196791,"issuer_key":"acme-v02.api.letsencrypt.org-directory","storage":"FileStorage:/data/caddy"}
caddy     | {"level":"debug","ts":1702425732.1125636,"logger":"tls.cache","msg":"added certificate to cache","subjects":["test2.datageeks.sk"],"expiration":1710196791,"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"ea62c445778f11c2c106850234b0ed2a904bbf6e3c9faa5505a2256bbad92f09","cache_size":1,"cache_capacity":10000}
caddy     | {"level":"debug","ts":1702425732.113007,"logger":"events","msg":"event","name":"cached_managed_cert","id":"5895ea4d-c7d7-49f3-a904-6fb3380da6f6","origin":"tls","data":{"sans":["test2.datageeks.sk"]}}
caddy     | {"level":"debug","ts":1702425732.113631,"logger":"tls","msg":"loading managed certificate","domain":"test.datageeks.sk","expiration":1710197161,"issuer_key":"acme-v02.api.letsencrypt.org-directory","storage":"FileStorage:/data/caddy"}
caddy     | {"level":"debug","ts":1702425732.1142232,"logger":"tls.cache","msg":"added certificate to cache","subjects":["test.datageeks.sk"],"expiration":1710197161,"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"d1a78d24cc9a15425ba2beb15f32b113dea251d0dd85d4a038ef05246297b43b","cache_size":2,"cache_capacity":10000}
caddy     | {"level":"debug","ts":1702425732.1145344,"logger":"events","msg":"event","name":"cached_managed_cert","id":"7df030d4-cf93-4336-b885-3ba5095adc41","origin":"tls","data":{"sans":["test.datageeks.sk"]}}
rstudio   | skipping /var/run/s6/container_environment/HOME
caddy     | {"level":"info","ts":1702425732.1155396,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
caddy     | {"level":"info","ts":1702425732.1158404,"msg":"serving initial configuration"}
caddy     | {"level":"info","ts":1702425732.1186175,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00044a680"}
caddy     | {"level":"warn","ts":1702425732.120799,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"d53e580a-d8e4-42b3-8f5e-fb55cea74e16","try_again":1702512132.1207955,"try_again_in":86399.999998778}
caddy     | {"level":"info","ts":1702425732.1211793,"logger":"tls","msg":"finished cleaning storage units"}
rstudio   | skipping /var/run/s6/container_environment/PASSWORD
rstudio   | skipping /var/run/s6/container_environment/RSTUDIO_VERSION
rstudio   | [cont-init.d] 01_set_env: exited 0.
rstudio   | [cont-init.d] 02_userconf: executing...
rstudio   | [cont-init.d] 02_userconf: exited 0.
rstudio   | [cont-init.d] done.
rstudio   | [services.d] starting services
ssh_test  | > shiny::runApp('/srv/shiny-server/app', host = '0.0.0.0', port = 3838)
rstudio   | [services.d] done.
ssh_test  | Loading required package: shiny
ssh_test  |
ssh_test  | Listening on http://0.0.0.0:3838

How are you trying to connect?

Use curl -v to make a request and show what you get.

@francislavoie
I made it working, the above Caddyfile configuration works.
Thank you very much for all your help and commitment.

What did you change to fix it?

Please explain the solution so that this doesn’t happen:

Sure.
As mentioned, the code above is correct, Caddyfile and Docker compose too.
Problem was the way I was accessing the apps. To call the app, I was generally used to put into browser this:

ip_address:port_number

After engaging Caddy, in line with my customs of the past, I did this:

http://my_domain_name:port_number
https://my_domain_name:port_number

This worked for http but did NOT for https. It took me a time to realize, that Caddy probably takes care of the port number, so I have to do this:

https://my_domain_name

WITHOUT port number
Then everything worked

1 Like

Yeah:

This config says “listen on the default port” which for HTTPS is 443.

Caddy acts like an HTTP router, it matches requests based on the hostname and handles them appropriately. It makes a new connection upstream with reverse_proxy on a specific port to access your app.

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