Hello! This is my first time using traefik and doing devops related tasks at my work, so I have been struggling setting up a simple POC of a deployed version of this docker-compose file in a EC2 instance:
As you can see, certificate and https configuration is not resolved yet, as Im trying to add that on my own. I have configured the domain to point to my IP (elastic IP) and managed to generate the certificate with letsencrypt.
I couldn't find the way to serve the app, neither through http or https. Starting the app, traefik logs me the following:
traefik-1 | 2024-08-31T19:58:55Z DBG github.com/traefik/traefik/v3/cmd/traefik/traefik.go:108 > Static configuration loaded [json] staticConfiguration={"api":{"dashboard":true,"insecure":true},"certificatesResolvers":{"myresolver":{"acme":{"caServer":"https://acme-v02.api.letsencrypt.org/directory","certificatesDuration":2160,"email":"benjamin.bascary@patagoniansys.com","keyType":"RSA4096","storage":"/letsencrypt/acme.json","tlsChallenge":{}}}},"entryPoints":{"traefik":{"address":":8080","forwardedHeaders":{},"http":{},"http2":{"maxConcurrentStreams":250},"transport":{"lifeCycle":{"graceTimeOut":"10s"},"respondingTimeouts":{"idleTimeout":"3m0s","readTimeout":"1m0s"}},"udp":{"timeout":"3s"}},"web":{"address":":80","forwardedHeaders":{},"http":{"redirections":{"entryPoint":{"permanent":true,"priority":9223372036854775806,"scheme":"https","to":"websecure"}}},"http2":{"maxConcurrentStreams":250},"transport":{"lifeCycle":{"graceTimeOut":"10s"},"respondingTimeouts":{"idleTimeout":"3m0s","readTimeout":"1m0s"}},"udp":{"timeout":"3s"}},"websecure":{"address":":443","forwardedHeaders":{},"http":{},"http2":{"maxConcurrentStreams":250},"transport":{"lifeCycle":{"graceTimeOut":"10s"},"respondingTimeouts":{"idleTimeout":"3m0s","readTimeout":"1m0s"}},"udp":{"timeout":"3s"}}},"experimental":{"plugins":{"headauth":{"moduleName":"github.com/poloyacero/headauth","settings":{},"version":"v0.0.1"},"keycloakopenid":{"moduleName":"github.com/Gwojda/keycloakopenid","settings":{},"version":"v0.1.34"}}},"global":{"checkNewVersion":true},"log":{"format":"common","level":"DEBUG"},"providers":{"providersThrottleDuration":"2s"},"serversTransport":{"maxIdleConnsPerHost":200},"tcpServersTransport":{"dialKeepAlive":"15s","dialTimeout":"30s"}}
And then a few more logs (sorry about the length)
traefik-1 | 2024-08-31T19:58:55Z INF github.com/traefik/traefik/v3/pkg/provider/aggregator/aggregator.go:202 > Starting provider *acme.ChallengeTLSALPN
traefik-1 | 2024-08-31T19:58:55Z DBG github.com/traefik/traefik/v3/pkg/provider/aggregator/aggregator.go:203 > *acme.ChallengeTLSALPN provider configuration config={}
traefik-1 | 2024-08-31T19:58:55Z INF github.com/traefik/traefik/v3/pkg/provider/aggregator/aggregator.go:202 > Starting provider *acme.Provider
traefik-1 | 2024-08-31T19:58:55Z DBG github.com/traefik/traefik/v3/pkg/provider/aggregator/aggregator.go:203 > *acme.Provider provider configuration config={"HTTPChallengeProvider":{},"ResolverName":"myresolver","TLSChallengeProvider":{},"caServer":"https://acme-v02.api.letsencrypt.org/directory","certificatesDuration":2160,"email":"benjamin.bascary@patagoniansys.com","keyType":"RSA4096","storage":"/letsencrypt/acme.json","store":{},"tlsChallenge":{}}
traefik-1 | 2024-08-31T19:58:55Z DBG github.com/traefik/traefik/v3/pkg/provider/acme/provider.go:213 > Attempt to renew certificates "720h0m0s" before expiry and check every "24h0m0s" acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme
traefik-1 | 2024-08-31T19:58:55Z INF github.com/traefik/traefik/v3/pkg/provider/acme/provider.go:795 > Testing certificate renew... acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme
traefik-1 | 2024-08-31T19:58:55Z DBG github.com/traefik/traefik/v3/pkg/server/configurationwatcher.go:227 > Configuration received config={"http":{"middlewares":{"dashboard_redirect":{"redirectRegex":{"permanent":true,"regex":"^(http:\\/\\/(\\[[\\w:.]+\\]|[\\w\\._-]+)(:\\d+)?)\\/$","replacement":"${1}/dashboard/"}},"dashboard_stripprefix":{"stripPrefix":{"prefixes":["/dashboard/","/dashboard"]}},"redirect-web-to-websecure":{"redirectScheme":{"permanent":true,"port":"443","scheme":"https"}}},"routers":{"api":{"entryPoints":["traefik"],"priority":9223372036854775806,"rule":"PathPrefix(`/api`)","ruleSyntax":"v3","service":"api@internal"},"dashboard":{"entryPoints":["traefik"],"middlewares":["dashboard_redirect@internal","dashboard_stripprefix@internal"],"priority":9223372036854775805,"rule":"PathPrefix(`/`)","ruleSyntax":"v3","service":"dashboard@internal"},"web-to-websecure":{"entryPoints":["web"],"middlewares":["redirect-web-to-websecure"],"priority":9223372036854775806,"rule":"HostRegexp(`^.+$`)","ruleSyntax":"v3","service":"noop@internal"}},"serversTransports":{"default":{"maxIdleConnsPerHost":200}},"services":{"api":{},"dashboard":{},"noop":{}}},"tcp":{"serversTransports":{"default":{"dialKeepAlive":"15s","dialTimeout":"30s"}}},"tls":{},"udp":{}} providerName=internal
Attempt on GET to https://intelligence.patagonian.com does not show any logs like Im not serving any entry point to outside the ec2 instance, which I suspect I messed up some config related to the networks on the dockerfile? It only returns 404 not found.
curl to all paths such as /, auth, or auth/admin ends in 404 also. This is the same curl output for all paths:
$ curl -v https://intelligence.patagonian.com/auth/admin
* Host intelligence.patagonian.com:443 was resolved.
* IPv6: (none)
* IPv4: 3.12.6.253
* Trying 3.12.6.253:443...
* Connected to intelligence.patagonian.com (3.12.6.253) port 443
* schannel: disabled automatic use of client certificate
* using HTTP/1.x
> GET /auth/admin HTTP/1.1
> Host: intelligence.patagonian.com
> User-Agent: curl/8.8.0
> Accept: */*
>
* Request completely sent off
* schannel: remote party requests renegotiation
* schannel: renegotiating SSL/TLS connection
* schannel: SSL/TLS connection renegotiated
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Sat, 31 Aug 2024 19:59:36 GMT
< Content-Length: 19
<
404 page not found
* Connection #0 to host intelligence.patagonian.com left intact
My docker-compose.yml file looks like the following:
services:
traefik:
image: "traefik:v3.1"
ports:
- 443:443
- 80:80
labels:
- traefik.enable=true
- traefik.docker.network=ragapp-network
# Keycloak OpenID plugin configuration
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.KeycloakURL=${KEYCLOAK_HOSTNAME}
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.ClientID=ragapp
# Secret from the example ragapp keycloak realm
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.ClientSecret=jh4yDlJ5QsBSafVNaqqLxEG3vKcYyNgD # Predefined secret for the example realm
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.KeycloakRealm=ragapp # Example realm
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.Scope=openid
# Admin authentication middleware
# 1. Use Keycloak user with role admin-manager
# Set UserClaimName and UserHeaderName to extract roles from the token and set them in the header for authorization
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.UserClaimName=X-Forwarded-Roles
- traefik.http.middlewares.ragapp-keycloakopenid.plugin.keycloakopenid.UserHeaderName=roles
# Use headauth plugin to check if the user has exactly the role admin-manager
- traefik.http.middlewares.admin-auth.plugin.headauth.header.name=roles
- traefik.http.middlewares.admin-auth.plugin.headauth.allowed[0]=[admin-manager]
- traefik.http.middlewares.admin-auth.plugin.headauth.methods[0]=GET
- traefik.http.middlewares.admin-auth.plugin.headauth.methods[1]=POST
- traefik.http.middlewares.admin-auth.plugin.headauth.methods[2]=PUT
- traefik.http.middlewares.admin-auth.plugin.headauth.methods[3]=DELETE
# 2. Alternative, we can just basicAuth for admin access. Please comment out the Keycloak middleware above and uncomment the following lines
# username: admin, password: admin
# - traefik.http.middlewares.admin-auth.basicauth.users=${USERNAME:-admin}:${HASHED_PASSWORD:-$$apr1$$3gG256rA$$BomHrC/uMhL807k/t7Wd6/}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${STATE_DIR}/traefik/traefik.yml:/traefik_config.yml:ro
- ./letsencrypt:/letsencrypt
command:
- --configFile=/traefik_config.yml
- --log.level=DEBUG
# - --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
networks:
- ragapp-network
keycloak:
image: quay.io/keycloak/keycloak:25.0.2
command: start-dev --import-realm --hostname=${KEYCLOAK_HOSTNAME}
ports:
- 8080:8080
labels:
- traefik.enable=true
- traefik.http.services.keycloak.loadbalancer.server.port=8080
- traefik.http.routers.keycloak.rule=PathPrefix(`/auth`)
- traefik.http.middlewares.keycloak-strip-path.stripprefix.prefixes=/auth
- traefik.http.routers.keycloak.middlewares=keycloak-strip-path
environment:
# Keycloak admin user (with all permissions to all realms)
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
volumes:
# Mount example realm data
- ${STATE_DIR}/keycloak/example/:/opt/keycloak/data/
networks:
- ragapp-network
depends_on:
- traefik
manager:
image: ${MANAGER_IMAGE:-ragapp/manager:latest}
build: ../../src/manager
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount the state folder to the manager
# Note: The container path `/app/data`, must be the same as the STATE_DIR_LOCAL
- ${STATE_DIR}:/app/data
environment:
- BASE_URL=/manager
- RAGAPP_IMAGE=${RAGAPP_IMAGE:-ragapp/ragapp:latest}
- CHAT_REQUEST_LIMIT_THRESHOLD=20
# The path in host machine where the state is stored (needed for creating volumes dynamically)
- STATE_DIR=${STATE_DIR}
# The path of the state inside of the manager container
- STATE_DIR_LOCAL=/app/data
labels:
- traefik.enable=true
- traefik.http.services.app.loadbalancer.server.port=8000
- traefik.http.routers.admin-manager.rule=PathPrefix(`/manager`)
- traefik.http.middlewares.strip-manager-path.stripprefix.prefixes=/manager
- traefik.http.routers.admin-manager.middlewares=ragapp-keycloakopenid,admin-auth,strip-manager-path
networks:
- ragapp-network
depends_on:
- traefik
- keycloak
networks:
ragapp-network:
name: ragapp-network
# Set as an external network to avoid conflicts.
external: true
I have a .env file with STATE_DIR as data and KEYCLOAK_HOST as https://intelligence.patagonian.com
and my traefik.yml file:
log:
level: DEBUG
api:
dashboard: true
insecure: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
myresolver:
acme:
tlschallenge: {}
email: benjamin.bascary@patagoniansys.com
storage: "/letsencrypt/acme.json"
experimental:
plugins:
keycloakopenid:
moduleName: "github.com/Gwojda/keycloakopenid"
version: "v0.1.34"
headauth:
moduleName: "github.com/poloyacero/headauth"
version: "v0.0.1"