1. My Caddy version (caddy -version
)
I am using caddy/caddy:alpine
in docker. Don’t know what version of 2 that is.
2. How I run Caddy:
a. System environment:
Digitalocean market place droplet Ubuntu Docker 5:19.03.1~3 on 18.04
c. Service/unit/compose file:
version: '3.7'
services:
db:
# specify container name to make it easier to run commands.
# for example, you could run docker exec -i postgres psql -U postgres postgres < schema.sql to run an SQL file against the Postgres database
container_name: ae_db
restart: always
image: db
build:
context: ./db
env_file:
- ./.env
networks:
- network
expose:
- '5432'
ports:
# make the Postgres database accessible from outside the Docker container on port 5432
- '5432:5432'
volumes:
- db_data:/var/lib/postgresql/data
- sik_data:/sik_data
graphql:
container_name: ae_graphql
restart: unless-stopped
build:
context: ./graphql
networks:
- network
expose:
- '5000'
ports:
- '5000:5000'
depends_on:
- db
env_file:
- ./.env
command:
[
'--connection',
'${DATABASE_URL}',
'--schema',
'ae',
'--append-plugins',
'postgraphile-plugin-connection-filter,@graphile-contrib/pg-order-by-related',
'--jwt-token-identifier',
'auth.jwt_token',
'--default-role',
'anon',
'--jwt-secret',
'${JWT_SECRET}',
'--cors',
'--disable-query-log',
'--enable-query-batching',
'--retry-on-init-fail',
]
json:
container_name: ae_json
restart: always
build:
context: ./json
networks:
- network
expose:
- '4000'
ports:
- '4000:4000'
depends_on:
- db
env_file:
- ./.env
caddy:
build:
context: ./caddy
container_name: ae_caddy
networks:
- network
depends_on:
- graphql
- json
restart: always
# image downgrades user but that seems not to work, see: https://caddy.community/t/basic-docker-compose-setup-failing/6892/7?u=alexander_gabriel
user: root
ports:
- '80:80'
- '443:443'
env_file:
- ./.env
volumes:
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
- caddy_certs:/root/.local/share/caddy
- caddy_config:/root/.config/caddy
volumes:
db_data:
sik_data:
caddy_certs:
caddy_config:
networks:
network:
d. My complete Caddyfile:
{
email alex.barbalex@gmail.com
}
direktbegruenung.ch {
# try proxying these - they should not be cross-domain
reverse_proxy /graphql* localhost:5000
reverse_proxy /graphiql* localhost:5000
reverse_proxy /artendb/* localhost:4000
reverse_proxy /evab* localhost:4000
reverse_proxy /alt* localhost:4000
root * /html
file_server
}
# original goal - but never worked
api.direktbegruenung.ch {
reverse_proxy /graphql* {
to localhost:5000
header_down Access-Control-Allow-Origin *
}
reverse_proxy /graphiql* {
to localhost:5000
header_down Access-Control-Allow-Origin *
}
reverse_proxy /evab* {
to localhost:4000
header_up Access-Control-Allow-Origin *
}
reverse_proxy /alt* {
to localhost:4000
header_down Access-Control-Allow-Origin *
}
}
# should work with:
# https.graphql.direktbegruenung.ch/graphql
# and
# https.graphql.direktbegruenung.ch/graphiql
graphql.direktbegruenung.ch {
reverse_proxy * localhost:5000 {
header_down Access-Control-Allow-Origin *
}
}
# should work with:
# https.json.direktbegruenung.ch/alt
# and
# https.json.direktbegruenung.ch/evab
json.direktbegruenung.ch {
reverse_proxy * localhost:4000 {
header_up Access-Control-Allow-Origin *
}
}
I have mixed header_up
and header_down
just so I have tried any possible combination.
The entire project is here: ae2/backend at master · FNSKtZH/ae2 · GitHub
3. The problem I’m having:
I have an app consisting of
- frontend (react-app)
- db: PostgreSQL listening on port 5432 which should also be reachable from outside (using PgAdmin)
- graphql-api: Postgraphile listening on port 5000
- json-api: hapi server listening on port 4000 (probably caddy could be used instead but this is for later)
The goal is to serve (I will refer to this as alternative 0
):
- frontend on
base-url.ch
- graphql-api on
api.base-url.ch/graphql
- graphiql on
api.base-url.ch/graphiql
- an api for an app called
alt
onapi.base-url.ch/alt
- an api for an app called
evab
onapi.base-url.ch/evab
Because this has been hard to achieve I have also tried two alternatives:
Alternative 1:
- frontend on
base-url.ch
- graphql-api on
graphql.base-url.ch/graphql
- graphiql on
graphql.base-url.ch/graphiql
- an api for an app called
alt
onjson.base-url.ch/alt
- an api for an app called
evab
onjson.base-url.ch/evab
Alternative 2:
- frontend on
base-url.ch
- graphql-api on
base-url.ch/graphql
- graphiql on
base-url.ch/graphiql
- an api for an app called
alt
onbase-url.ch/alt
- an api for an app called
evab
onbase-url.ch/evab
Alternative 1 separates subdomains by service which might make routing simpler.
Alternative 2 should hopefully eliminate cross origin requests as api and app are on the exact same domain.
Unfortunately I have gotten none of these alternatives to work correctly. I have read the documentation repeatedly and searched the internet for examples. But I am pretty sure that I have misunderstood how this is supposed to be done because I simply do not know how it is meant to be done. Also I am a frontend guy, not versed in this backend code. But the problem should be rather common, I should think.
Building caddy results in this log:
root@artdaten:~/ae# docker logs ae_caddy
2020/02/05 10:45:15.563 INFO using provided configuration {"config_file": "/etc/caddy/Caddyfile", "config_adapter": "caddyfile"}
2020/02/05 10:45:15.620 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["localhost:2019"]}
2020/02/05 10:45:15.620 INFO http 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}
2020/02/05 10:45:15.620 INFO http enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2020/02/05 10:45:15.621 INFO http enabling automatic TLS certificate management {"domains": ["direktbegruenung.ch", "graphql.direktbegruenung.ch", "json.direktbegruenung.ch", "api.direktbegruenung.ch"]}
2020/02/05 10:45:15.633 INFO tls cleaned up storage units
2020/02/05 10:45:15.633 INFO autosaved config {"file": "/root/.config/caddy/autosave.json"}
2020/02/05 10:45:15.633 INFO serving initial configuration
2020/02/05 10:45:15 [INFO][cache:0xc00009c0a0] Started certificate maintenance routine
…so that seems to work o.k.?
4. Error messages and/or full log output:
Here are the issues, grouped by alternative solutions:
Alternative 0:
curl https://api.direktbegruenung.ch/graphql
returns nothing. This appears in the log:
root@artdaten:~/ae# docker logs ae_caddy --since 2m
2020/02/05 10:32:29.188 ERROR http.log.error dial tcp 127.0.0.1:5000: connect: connection refused {"request": {"method": "GET", "uri": "/graphql", "proto": "HTTP/2.0", "remote_addr": "167.172.187.231:50708", "host": "direktbegruenung.ch", "headers": {"User-Agent": ["curl/7.58.0"], "Accept": ["*/*"]}, "tls": {"resumed": false, "version": 772, "ciphersuite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "direktbegruenung.ch"}}, "status": 502, "err_id": "6naxtqce4", "err_trace": "reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:362)"}
2020/02/05 10:33:33 [INFO][cache:0xc00022f360] Scanning for stale OCSP staples
2020/02/05 10:33:33 [INFO][cache:0xc00022f360] Done checking OCSP staples
curl -v https://api.direktbegruenung.ch/graphql
returns:
root@artdaten:~/ae# curl -v https://api.direktbegruenung.ch/graphql
* Trying 167.172.187.231...
* TCP_NODELAY set
* Connected to api.direktbegruenung.ch (167.172.187.231) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Client hello (1):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=api.direktbegruenung.ch
* start date: Feb 4 22:14:58 2020 GMT
* expire date: May 4 22:14:58 2020 GMT
* subjectAltName: host "api.direktbegruenung.ch" matched cert's "api.direktbegruenung.ch"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* Using Stream ID: 1 (easy handle 0x558b7e342580)
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
> GET /graphql HTTP/2
> Host: api.direktbegruenung.ch
> User-Agent: curl/7.58.0
> Accept: */*
>
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
< HTTP/2 502
< server: Caddy
< content-length: 0
< date: Wed, 05 Feb 2020 10:23:49 GMT
<
* Connection #0 to host api.direktbegruenung.ch left intact
Using https://api.direktbegruenung.ch/graphql
from the frontend results in this logged in the console:
Access to fetch at 'https://api.direktbegruenung.ch/graphql' from origin 'https://direktbegruenung.ch' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Alternative 1:
curl https://graphql.direktbegruenung.ch/graphql
returns nothing.
This appears in the logs:
root@artdaten:~/ae# docker logs ae_caddy --since 2m
2020/02/05 10:34:55.260 ERROR http.log.error dial tcp 127.0.0.1:5000: connect: connection refused {"request": {"method": "GET", "uri": "/graphql", "proto": "HTTP/2.0", "remote_addr": "167.172.187.231:50716", "host": "graphql.direktbegruenung.ch", "headers": {"User-Agent": ["curl/7.58.0"], "Accept": ["*/*"]}, "tls": {"resumed": false, "version": 772, "ciphersuite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "graphql.direktbegruenung.ch"}}, "status": 502, "err_id": "a4cgjkmyu", "err_trace": "reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:362)"}
curl -v https://graphql.direktbegruenung.ch/graphql
returns:
root@artdaten:~/ae# curl -v https://graphql.direktbegruenung.ch/graphql
* Trying 167.172.187.231...
* TCP_NODELAY set
* Connected to graphql.direktbegruenung.ch (167.172.187.231) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Client hello (1):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=graphql.direktbegruenung.ch
* start date: Feb 4 22:14:57 2020 GMT
* expire date: May 4 22:14:57 2020 GMT
* subjectAltName: host "graphql.direktbegruenung.ch" matched cert's "graphql.direktbegruenung.ch"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* Using Stream ID: 1 (easy handle 0x5639e2007580)
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
> GET /graphql HTTP/2
> Host: graphql.direktbegruenung.ch
> User-Agent: curl/7.58.0
> Accept: */*
>
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
< HTTP/2 502
< server: Caddy
< content-length: 0
< date: Wed, 05 Feb 2020 10:30:16 GMT
<
* Connection #0 to host graphql.direktbegruenung.ch left intact
Using https://graphql.direktbegruenung.ch/graphql
from the frontend results in this logged in the console:
Access to fetch at 'https://graphql.direktbegruenung.ch/graphql' from origin 'https://direktbegruenung.ch' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Alternative 2:
curl https://direktbegruenung.ch/graphql
returns nothing.
This appears in the logs:
root@artdaten:~/ae# docker logs ae_caddy --since 1m
2020/02/05 10:35:50.733 ERROR http.log.error dial tcp 127.0.0.1:5000: connect: connection refused {"request": {"method": "GET", "uri": "/graphql", "proto": "HTTP/2.0", "remote_addr": "167.172.187.231:50722", "host": "direktbegruenung.ch", "headers": {"User-Agent": ["curl/7.58.0"], "Accept": ["*/*"]}, "tls": {"resumed": false, "version": 772, "ciphersuite": 4865, "proto": "h2", "proto_mutual": true, "server_name": "direktbegruenung.ch"}}, "status": 502, "err_id": "j9eiqsmht", "err_trace": "reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:362)"}
curl -v https://direktbegruenung.ch/graphql
returns:
root@artdaten:~/ae# curl -v https://direktbegruenung.ch/graphql
* Trying 167.172.187.231...
* TCP_NODELAY set
* Connected to direktbegruenung.ch (167.172.187.231) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Client hello (1):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=direktbegruenung.ch
* start date: Feb 4 22:14:56 2020 GMT
* expire date: May 4 22:14:56 2020 GMT
* subjectAltName: host "direktbegruenung.ch" matched cert's "direktbegruenung.ch"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* Using Stream ID: 1 (easy handle 0x55c83dd1e580)
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
> GET /graphql HTTP/2
> Host: direktbegruenung.ch
> User-Agent: curl/7.58.0
> Accept: */*
>
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
< HTTP/2 502
< server: Caddy
< content-length: 0
< date: Wed, 05 Feb 2020 10:32:29 GMT
<
* Connection #0 to host direktbegruenung.ch left intact
Using https://direktbegruenung.ch/graphql
from the frontend results in this logged in the console:
POST https://direktbegruenung.ch/graphql 502
5. What I already tried:
Searched docs, issues and the internet. Tried many combinations of how I thought it maybe should be done.