Using Traefik to reverse proxy Grafana at a suburl; 404 responses - grafana

I have tried my best to follow the documentation for both Grafana and Traefik to reverse proxy incoming requests to https://metrics.mydomain/grafana through Traefik to a Grafana instance running as a container, but I get 404 responses from Grafana and I can't figure out why.
Here's what I've done after reading docs and trying various things in my docker-compose.yml file:
version: '3'
services:
traefik:
image: traefik
restart: always
ports:
- 80:80
- 443:443
- 8080:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /home/ben/traefik.toml:/etc/traefik/traefik.toml
- /etc/letsencrypt/live/mydomain/fullchain.pem:/mydomain_fullchain.pem
- /etc/letsencrypt/live/mydomain/privkey.pem:/mydomain_privkey.pem
grafana:
image: grafana/grafana
restart: always
ports:
- 3000:3000
volumes:
- /srv/grafana:/var/lib/grafana
environment:
- GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/grafana
labels:
- traefik.enable=true
- 'traefik.frontend.rule=Host:metrics.mydomain;PathPrefix:/grafana;'
- 'traefik.frontend.redirect.entryPoint=https'
Traefik does pick up on this. Here's what it shows on the dashboard:
However, when I actually request https://metrics.mydomain/grafana, what I get back is 404 and an error document, and then subsequent 404s for the resources requested by the custom error document:
Finally, and most confusingly, it appears that the requests as received by Grafana itself are correct, but still result in 404s:
method=GET path=/grafana status=404 remote_addr=192.168.0.1
method=GET path=/grafana/public/build/grafana.dark.css status=404 remote_addr=192.168.0.1
...etc
I don't understand why this is so fussy, and there doesn't appear (to me) to be any evidence that would suggest what the actual problem is.
p.s. - I did leave a comment on a Grafana issue that looked relevant. https://github.com/grafana/grafana/issues/2066#issuecomment-380647174

I was able to fix this by using PathPrefixStrip instead of PathPrefix

This issue is resolved as I write this in the latest image. I was experiencing the same issue with grafana/grafana:5.1.0.
My working configuration for reference:
version: '2'
services:
grafana:
image: grafana/grafana
environment:
- GF_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/grafana
- GF_SERVER_DOMAIN=devserver1.mydomain
- GF_SERVER_SERVE_FROM_SUB_PATH=true
labels:
- "traefik.http.routers.grafana.rule=Host(`devserver1.mydomain`) && PathPrefix(`/grafana`)"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
networks:
- traefik_default
volumes:
- grafana-storage:/var/lib/grafana
networks:
traefik_default:
external: true
volumes:
grafana-storage:
Grafana's documentation on running behind a reverse proxy Run Grafana behind a reverse proxy. An explanation on how to Configure with environment variables.

Related

Traefik with multiple docker-compose.yml files

Hello traefik friends.
I just started to look into traefik. All tutorials show how to run one docker-compose.yml file with traefik togather with other containers. I most often have many separate docker-compose.yml files and very much would like to use them with traefik.
so here is my code for traefik container:
version: "3.3"
services:
traefik:
image: "traefik:v2.5"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
#- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.myresolver.acme.email=xxxxxxxxx#gmail.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "8080:8080"
networks:
- "traefik"
- "external"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
and the other exemplary docker-compose I would like to use with traefik:
version: '3.1'
services:
php:
image: php:7.4-apache
ports:
- 8081:80
volumes:
- ./php/www:/var/www/html/
labels:
- "traefik.enable=true"
- "traefik.http.routers.php.rule=host(`php.xxxxxx.com`)"
- "traefik.http.routers.php.entrypoints=websecure"
- "traefik.http.routers.php.tls.certresolver=myresolver"
unfortunately that doesnt seem to work (when I concat theese to files into one big docker-compose.yml file - it works fine. Could you point me in the right direction?
Traefik needs to be part of the networks for all the services it connects to. For me it works when I set network: host for Traefik. (And then you have to remove ports part.)
I do wonder how safe that is, I can't seem to access the admin interface from another machine, so that's good.
Each docker-compose.yml by default create its own network. So traefik from the traefik network can't access PHP server from some other "php-default" network.
see Compose Networking docs
We have to add the PHP server to the traefik network:
php/docker-compose.yml:
services:
php:
image: php:7.4-apache
# we need to tell the traefik what port is the container listening to
expose:
- 80
volumes:
- ./php/www:/var/www/html/
labels:
- "traefik.enable=true"
- "traefik.http.routers.php.rule=host(`php.xxxxxx.com`)"
- "traefik.http.routers.php.entrypoints=websecure"
- "traefik.http.routers.php.tls.certresolver=myresolver"
networks:
default:
name: traefik
external: true
OR if you want to have other networks
services:
php:
...
networks:
- traefik
...
networks:
traefik:
external: true
Note there is not defined port property, instead there is expose. The port exposes ports on the host, the expose act as mere documentation (see this Q) but the traefik read it.
And because of that, I think that in your traefik/docker-compose.yml the external network is unnecessary.

Traefik 2 Gateway Timeout

So I have the following docker-compose.yml
version: "3.7"
services:
roundclinic-mysql:
image: mysql:5.7
networks:
- spring-boot-mysql-network
environment:
- MYSQL_DATABASE=
- MYSQL_USER=
- MYSQL_PASSWORD=
- MYSQL_ROOT_PASSWORD=
volumes:
- ./mysqldata:/var/lib/mysql:rw,delegated
ports:
- "3306:3306"
web-service:
image: roundclinic/roundclinic:latest
networks:
- spring-boot-mysql-network
- traefik-network
depends_on:
- roundclinic-mysql
ports:
- 8080:8080
environment:
- "SPRING_PROFILES_ACTIVE=dev"
links:
- roundclinic-mysql
labels:
- "--providers.docker.network=traefik_default"
- "traefik.enable=true"
- "traefik.http.routers.roundclinic.rule=Host(`api-dev.roundclinic.app`)"
- "traefik.http.routers.roundclinic.entrypoints=web"
- "traefik.http.services.cal.loadbalancer.server.port=8080"
traefik:
image: "traefik:v2.2"
container_name: "traefik"
command:
- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "traefik.docker.network=traefik-network"
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
traefik-network:
driver: bridge
external: true
spring-boot-mysql-network:
driver: bridge
volumes:
my-db:
Spring boot starts up fine and can connect to mysql.
When I connect to http://api-dev.roundclinic.app:8080/../ I can hit my application just fine
When I connect to http://api-dev.roundclinic.app/../ I get a gateway timeout. I can see in the traefik logs that it's forwarding the request to what seems to be the correct IP and port, but nothing hits the actual application. I'm not sure what's going on here. Any help?
When accessing port 8080 you are bypassing Traefik and directly access your application, correct?
Generally speaking the Traefik labels look good. Entrypoint, Port and Host are defined, router and service port are present. These are usually all the requirements for Docker-based setups.
One thing that I noticed is that the traefik container uses "traefik.docker.network=traefik-network", but your web app uses:
"--providers.docker.network=traefik_default".
I am not sure if traefik_default is something that traefik provides but that mismatch in network names might be the issue.
I can't test if that is the problem but that would be the first thing to check.
One way would be to simplify your config but just always using the networks key from docker compose instead of mixing it with labels and arguments.

Traefik intermittent 404 on docker-compose

I'm running a bunch of services behind a traefik reverse proxy. I have tested those services to death and they work great. The problem is that when traefik is involved I get intermittent 404 errors whhenever I interact with them.
One of those services exposes a nice and simple REST api. Consuming code has to retry all requests. This is managable.
One of thse services exposes a frontend: If I want to use the frontend I have to constantly refresh the page. This is a truely aweful user experience.
Here are some samples from my compose file:
version: "2.1"
services:
reverse-proxy:
image: traefik:v2.2
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
ports:
- "8081:80"
- "8082:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
api_service:
image: its_just_a_flask_app
labels:
- "traefik.enable=true"
- "traefik.http.routers.configrouter1.rule=PathPrefix(`/config_backend/`) && (Method(`GET`) || Method(`POST`))"
- "traefik.http.routers.configrouter1.middlewares=config-backend-auth#docker"
- "traefik.http.middlewares.config-backend-auth.basicauth.usersfile=/config/usersfile"
webserver:
image: puckel/docker-airflow:with_a_few_lil_tweaks
restart: always
depends_on:
- postgres # these exist and work fine
- redis
environment:
- LOAD_EX=n
- FERNET_KEY=stuff=
- EXECUTOR=Celery
- AIRFLOW__WEBSERVER__BASE_URL=http://webserver/airflow
volumes:
- ../orchistrator/dags/:/usr/local/airflow/dags
- ./requirements.txt:/requirements.txt
command: webserver
healthcheck:
test: ["CMD-SHELL", "[ -f /usr/local/airflow/airflow-webserver.pid ]"]
interval: 30s
timeout: 30s
retries: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.aurflowrouter.rule=PathPrefix(`/airflow`)"
- "traefik.http.routers.aurflowrouter.middlewares=airflow-basic-auth#docker"
- "traefik.http.middlewares.airflow-basic-auth.basicauth.usersfile=/config/usersfile"
- traefik.http.services.my-service.loadbalancer.server.port=8080
As you can see both of these use basic auth. removing the auth has no effect
removing the webserver's healthcheck has no effect
when making api calls to the api_service, the first call often fails, the second call always succeeds
when accessing the airflow frontend: the first page load fails, after that it succeeds.
theres a button on the airflow fronend that triggers a POST. The POST returns a 302 Found, then the redirect always gives me a 404 at first
sometimes the web frontend oads, but the static resources that it relies on do not load, resulting in an ugly and unusable site. So I find myself refreshing the page a lot
I'm at a loss here. Any help would be very apprectiated.
Traefik tags I've tried:
Sinve the only advice I've recieved or found so far is about using old tags or new tags, here's what I've found
image: traefik:v2.2
image: traefik:v2.2.1
image: traefik:v2.2.5
image: traefik:latest
I got similar issues after pulling traefik:latest yesterday.
Just noticed the image was updated today and a new pull fixed my issues.
Turned out it was a bug on v2.2.2. See here for more. Use, for example, v2.2.5 to get rid of this problem

traefik v2.2 help using only docker-compose router service entrypoint

Started learning about docker, traefik for playing in home.
Aim: Put everything all together in docker-compose.yml and .env files, understand basics, comment accordingly.
Want to get dashboard from traefik.test.local/dashboard rather test.local:8080, similarly api should be accessed from traefik.test.local/api. So that don't have to think about port numbers.
added lines to /etc/hosts
127.0.0.1 test.local
127.0.0.1 traefik.test.local
docker-compose.yml
version: "3.7"
services:
traefik:
# The official v2 Traefik docker image
image: traefik:v2.2
# Lets name the container
container_name: traefik
command:
# Enables the web UI
- "--api.insecure=true"
# Tells Traefik to listen to docker
- "--providers.docker"
ports:
# The HTTP port
- "80:80"
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
#labels:
#- "traefik.http.routers.router.rule=Host(`traefik.test.local/dashboard`)"
#- "traefik.http.routers.router.rule=Host(`traefik.test.local/api`)"
restart:
always
Not able to understand how to connect from router to services. Also correct me if I am wrong anywhere. Thank you.
PS: OS: kde-neon
you can achieve this using the following definition, you need to add labels for the routers and service and not only the router
proxy:
image: traefik:v2.1
command:
- '--providers.docker=true'
- '--entryPoints.web.address=:80'
- '--entryPoints.metrics.address=:8082'
- '--providers.providersThrottleDuration=2s'
- '--providers.docker.watch=true'
- '--providers.docker.swarmMode=true'
- '--providers.docker.swarmModeRefreshSeconds=15s'
- '--providers.docker.exposedbydefault=false'
- '--providers.docker.defaultRule=Host("traefik.lvh.me")'
- '--accessLog.bufferingSize=0'
- '--api=true'
- '--api.dashboard=true'
- '--api.insecure=true'
- '--ping.entryPoint=web'
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
ports:
- '80:80'
- '8080:8080'
restart:
always
deploy:
labels:
- traefik.enable=true
- traefik.docker.network=monitoring
- traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080
- traefik.http.routers.traefik-dashboard.rule=Host(`dashboard.traefik.lvh.me`)
- traefik.http.routers.traefik-dashboard.service=traefik-dashboard
- traefik.http.routers.traefik-dashboard.entrypoints=web
- traefik.http.services.traefik-api.loadbalancer.server.port=80
- traefik.http.routers.traefik-api.rule=Host(`api.traefik.lvh.me`)
- traefik.http.routers.traefik-api.service=traefik-api
- traefik.http.routers.traefik-api.entrypoints=web
logging:
driver: json-file
options:
'max-size': '10m'
'max-file': '5'
also if you use lvh.me domain you not need to edit /etc/hosts

Traefik docker-compose only creating one frontend route instead of 3

I want traefik to routh specific paths to my nginx service.
The setup below works on my development environment, but not on a live
environment.
The issue is, for the nginx service it only ever creates one of the frontend
routes, usually just static, or just media. It's as if it finds one, creates it
and then just doesn't bother with the rest.
If I restart my containers, then traefik will randomly do only one of the routes
again, but never all 3 as it does on my dev machine.
docker-compose.yml
version: '3'
services:
db:
image: postgres:latest
webapp:
build:
context: ./src/webapp/
env_file:
- .env
volumes:
- "./resources:/mnt/resources/"
depends_on:
- db
links:
- "db:dbhost"
labels:
- "traefik.backend=webapp"
- "traefik.port=8000"
- "traefik.webapp.entryPoints=https"
- "traefik.webapp.frontend.rule=Host:my.domain.example"
nginx:
build:
context: ./src/nginx/
volumes:
- ./resources:/mnt/resources
labels:
- "traefik.backend=nginx"
- "traefik.port=443"
- "traefik.frontend.entryPoints=https"
- "traefik.static.frontend.rule=Host:my.domain.example;PathPrefix:/static"
- "traefik.media.frontend.rule=Host:my.domain.example;PathPrefix:/media"
- "traefik.sw.frontend.rule=Host:my.domain.example;Path:/service-worker.js"
traefik:
image: traefik:1.6.3
restart: always
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./src/traefik/traefik.toml:/traefik.toml
- ./src/traefik/acme.json:/acme.json
A separate question but still traefik related:
Traefik is supposed to fetch letsencrypt certs for the main.domain, and does so
perfectly well for that domain.
But it's also trying to fetch certs for the db and traefik service.
How do I tell traefik not to fetch certs for these services?
Finally figured it out.
For the frontends that weren't generated, I basically had to specify a backend for each frontend, and then they worked as expected.
so this:
- "traefik.static.frontend.rule=Host:my.domain.example;PathPrefix:/static"
- "traefik.media.frontend.rule=Host:my.domain.example;PathPrefix:/media"
- "traefik.sw.frontend.rule=Host:my.domain.example;Path:/service-worker.js"
... became this:
- "traefik.static.backend=nginx-static"
- "traefik.static.frontend.rule=Host:my.domain.example;PathPrefix:/static"
- "traefik.media.backend=nginx-media"
- "traefik.media.frontend.rule=Host:my.domain.example;PathPrefix:/media"
- "traefik.sw.backend=nginx-sw"
- "traefik.sw.frontend.rule=Host:my.domain.example;Path:/service-worker.js"
After that everything worked correctly.