I have a very simple setup with with Traefik using Docker & Let's Encrypt to proxy incoming requests to an API service.
All is up and running well except that client's can't make requests to the API because of CORS.
How can I add Origin, Content-Type, and Authorization headers so I can ensure they reach my Node API running behind the proxy and ensure Access-Control-Allow-Origin are kept in the response headers?
My traefik.toml file:
debug = false
logLevel = "ERROR"
defaultEntryPoints = ["https","http"]
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[retry]
[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "<hostname-here>"
watch = true
exposedByDefault = false
[acme]
email = "<your-email-here>"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
[acme.httpChallenge]
entryPoint = "http"
My docker-compose.yml that runs my API:
version: "2"
services:
app:
build:
context: .
dockerfile: Dockerfile-App
environment:
- NODE_ENV=${NODE_ENV}
restart: always
networks:
- web
- default
expose:
- "5000"
labels:
- "traefik.docker.network=web"
- "traefik.enable=true"
- "traefik.basic.frontend.rule=Host:${HOSTNAME}"
- "traefik.frontend.auth.forward.trustForwardHeader=true"
- "traefik.frontend.passHostHeader=true"
- "traefik.basic.port=5000"
- "traefik.basic.protocol=http"
networks:
web:
external: true
The docs imply you can add customHeaders
traefik.frontend.headers.customResponseHeaders=EXPR Appends the headers to each response returned by the container, before forwarding the response to the client.
Format: HEADER:value||HEADER2:value2
But how am I supposed to know the value of dynamic values such as Authorization Tokens?
EDIT:
I tried adding a custom header like this:
- "traefik.frontend.headers.customResponseHeaders=Access-Control-Allow-Origin: *"
But that's not being appended to the response headers at all.
entrypoint > Router > Middleware > Service
I think you should create the middleware first then attach it to the specific router:
I got the headers added to the response by adding these labels to my service :
...
- "traefik.http.routers.frontend.entrypoints=http"
#creating middleware for headers
- "traefik.http.middlewares.frontend.headers.customresponseheaders.Access-Control-Allow-Methods=POST, GET, PUT, OPTIONS, DELETE"
- "traefik.http.middlewares.frontend.headers.customresponseheaders.Access-Control-Allow-Origin=*"
- "traefik.http.middlewares.frontend.headers.customresponseheaders.Access-Control-Allow-Headers=x-requested-with, Content-Type,Authorization"
#attach middleware to the frontend router
- "traefik.http.routers.frontend.middlewares=frontend"
I was conditionally resolving CORS in my nodejs application based on the Origin of the request in an effort to white-list host names, but the origin wasn't being set by Traefik properly. I removed the conditional and white-listed host names with Traefik instead.
After doing this, CORS works properly and my labels above are sound.
Related
I have configured nginx and given hostname to keycloak as http://keycloak.formsflow.ai for localhost:8080, but as I see in redirection url it show port number 8080, how can I remove it?
Keycloak showing port number in redirection along with hostname
Below is my docker config for keycloak
keycloak:
image: quay.io/keycloak/keycloak:14.0.0
container_name: keycloak
volumes:
- ./configuration/imports:/opt/jboss/keycloak/imports
command:
- "-b 0.0.0.0 -bmanagement=0.0.0.0 -Dkeycloak.import=/opt/jboss/keycloak/imports/formsflow-ai-realm.json -Dkeycloak.migration.strategy=OVERWRITE_EXISTING"
environment:
- DB_VENDOR=POSTGRES
- DB_ADDR=keycloak-db
- KEYCLOAK_HOSTNAME=keycloak.formsflow.ai
- DB_DATABASE=${KEYCLOAK_JDBC_DB:-keycloak}
- DB_USER=${KEYCLOAK_JDBC_USER:-admin}
- DB_PASSWORD=${KEYCLOAK_JDBC_PASSWORD:-changeme}
- KEYCLOAK_USER=${KEYCLOAK_ADMIN_USERNAME:-admin}
- KEYCLOAK_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD:-changeme}
ports:
- 8080:8080
config to set for keycloak to remove port number from redirection url
When behind a reverse proxy, configure Keycloak properties:
PROXY_ADDRESS_FORWARDING=true
KEYCLOAK_FRONTEND_URL=http://keycloak.formsflow.ai/auth
You may also need to configure headers X-Forwarded-Proto and X-Forwarded-Host in Nginx.
The minimal example from https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/ works on my local machine. However, when I try to adapt this to use TLS I run into an issue. I'm a Traefik newbie, so I might be doing a stupid mistake.
This is my attempt:
version: "3.3"
services:
traefik:
image: "traefik:v2.8"
container_name: "traefik"
command:
- "--log.level=DEBUG"
- "--accesslog=true"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "443:443"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
image: "traefik/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`127.0.0.1`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
So the major modification is to use "traefik.http.routers.whoami.entrypoints=websecure" instead of "traefik.http.routers.whoami.entrypoints=web"
Running
$ curl -k https://127.0.0.1
I get
404 page not found
The traefik log shows no routing related issues and the internal traefik setup for routing etc shown using curl https://127.0.0.1:8080/api/rawdata | jq . looks the same as the one of the working example, except the changed port.
So I opted for new answer instead of just editing the old answer. (Reason being even incorrect answers teach something).
My reference is this great post by Marc Mogdanz (link: https://marcmogdanz.de/posts/infrastructure-with-traefik-and-cloudflare/).
The direct answer to your query is:
Expose port 8080 but do not publish it
Add a host name rule. This will allow Traefik to route a URL request to its own port 8080.
The affected part of the compose file would be as follows (assuming that the URL https://dashboard.example.com is the desired URL to reach the dashboard):
expose:
- 8080
...
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`dashboard.example.com`)"
- "traefik.http.routers.traefik.tls=true"
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
Finally, I noticed you are testing on localhost. If you are testing on a local machine, use localhost for the dashboard and keep 127.0.0.1 for whoami.
Or, alternately, add a static entry for a subdomain (see https://stackoverflow.com/a/19016600).
Either way, Traefik is looking at the SNI requested - not necessarily the IP address - when matching the Host rule.
Request ----> Docker:443 ---> {Traefik}-"SNI?"---"127.0.0.1"---> {whoami}
| \
| \
8080<---"dashboard.localhost"
Add the following entry to your Traefik:
"--entrypoints.websecure.address=:8080"
Normally it would be 8080 for http and 8443 for https alternative ports, but since your example specifically states https://~:8080, I have adapted it accordingly.
I would like to serve a docker-compose service through traefik with port-forwarding. I had many tries and the best I could achieve from now is described below:
First I create two networks:
docker network create frontend # To expose traefik
docker network create backend # To bind backend services
The traefik configuration is about (development, dashboard enabled at :8080):
version: "3.6"
services:
proxy:
image: traefik:latest
restart: unless-stopped
command:
- "--log.level=DEBUG"
- "--api"
- "--api.dashboard"
- "--api.insecure"
- "--providers.docker"
- "--providers.docker.exposedbydefault=false"
# Service entrypoint:
- "--entrypoints.lora-server.address=:8090"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
labels:
- "traefik.enable=true"
- "traefik.docker.network=frontend"
- "traefik.http.routers.traefik.entrypoints=traefik"
- "traefik.http.routers.traefik.service=api#internal"
networks:
- backend
- frontend
ports:
- "8080:8080"
- "8090:8090"
networks:
frontend:
external: true
backend:
external: true
The backend service is described here (a fork from ChripStack but it could be anything else):
version: "3"
services:
# [...]
chirpstack-application-server:
image: chirpstack/chirpstack-application-server:3
networks:
- backend
volumes:
- ./configuration/chirpstack-application-server:/etc/chirpstack-application-server
labels:
- "traefik.enable=true"
- "traefik.docker.network=backend"
- "traefik.http.routers.chirpstack.entrypoints=lora-server"
- "traefik.http.routers.chirpstack.rule=Host(`{host:}`)"
- "traefik.http.routers.chirpstack.service=chirpstack-application-server#docker"
- "traefik.http.services.chirpstack-application-server.loadbalancer.server.port=8080"
# [...]
networks:
backend:
external: true
The service also natively run on :8080 and I would like to access it on :8090 through traefik.
When I run both applications, traefik registers the new service and does not complain (no errors, no warning, the flow seems complete at least from the dashboard interface).
time="2020-07-30T11:47:47Z" level=debug msg="Creating middleware" middlewareType=Pipelining serviceName=chirpstack-application-server#docker entryPointName=lora-server routerName=chirpstack#docker middlewareName=pipelining
time="2020-07-30T11:47:47Z" level=debug msg="Creating load-balancer" entryPointName=lora-server routerName=chirpstack#docker serviceName=chirpstack-application-server#docker
time="2020-07-30T11:47:47Z" level=debug msg="Creating server 0 http://192.168.112.9:8080" entryPointName=lora-server routerName=chirpstack#docker serviceName=chirpstack-application-server#docker serverName=0
time="2020-07-30T11:47:47Z" level=debug msg="Added outgoing tracing middleware chirpstack-application-server#docker" middlewareName=tracing entryPointName=lora-server routerName=chirpstack#docker middlewareType=TracingForwarder
But I could not access the service, I am geting 404 errors when I try to connect http://host:8090.
To my understanding, it seems traefik does not know how it should complete the flow between the two networks: http://frontend:8090 -> http://backend:8080 (because I haven't referenced it anywhere).
What should I change in my configuration to make it work? How can I specify to traefik that it must route the HTTP traffic from frontend:8090 to backend:8080? Your help is much appreciated.
Traefik listens on some port, that's the only thing defined with entrypoints. You don't specify network for this incoming requests, because it's unrelated. traefik.docker.network is only used for routing after Traefik handles the incoming requests.
So the correct flow is not http://frontend:8090 -> http://backend:8080, but http://host:8090 -> http://backend:8080.
I think your configuration is correct. The only thing which seems to be odd is usage of Host rule. Maybe try to change it to something like this:
"traefik.http.routers.chirpstack.rule=hostregexp(`{host:.+}`)"
I'm trying to do a reverse proxy with Traefik, like Nginx.
To resume, I would like a proxies requests from a certain endpoint onto a local network port, that happens to be a SSH tunnel with Traefik.
Actually it works with Nginx but Would like to stop using Nginx instead of Traefik.
I already test some configs but the Home Assistant Add-on (Autossh) doesn't connect to it.
(It works like a charm with Nginx in the same server).
Here, my Traefik configuration :
docker-compose.yml
version: '3.7'
services:
reverse-proxy:
restart: always
image: traefik:chevrotin
ports:
- "443:443"
- "80:80"
volumes:
- /srv/traefik.toml:/etc/traefik/traefik.toml
- /srv/services.toml:/etc/traefik/services.toml
- /var/run/docker.sock:/var/run/docker.sock
- /srv/acme.json:/acme.json
labels:
- "traefik.http.routers.api.rule=Host(`dashboard.domain.com`)"
- "traefik.http.routers.api.service=api#internal"
- "traefik.http.routers.api.entrypoints=http"
- traefik.http.routers.nas.entrypoints=https
- traefik.http.routers.nas.rule=Host(`home-assistant.domain.com`)
- traefik.http.routers.nas.service=nas#file
- traefik.http.routers.nas.tls=true
- traefik.http.routers.nas.tls.certresolver=letsencrypt
traefik.toml
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.https]
address = ":443"
[api]
[providers.docker]
endpoint = "unix:///var/run/docker.sock"
[providers.file]
filename = "/etc/traefik/services.toml"
[certificatesResolvers.letsencrypt.acme]
email = "contact#domain.com"
storage = "acme.json"
[certificatesResolvers.letsencrypt.acme.httpChallenge]
entryPoint = "http"
services.toml
[http]
[http.services]
[http.services.nas]
[http.services.nas.loadBalancer]
[[http.services.nas.loadBalancer.servers]]
url = "http://localhost:44400"
I have the newest Omnibus GitLab Docker image, and the docker-compose.yml looks like this:
web:
image: 'gitlab/gitlab-ce:latest'
restart: always
hostname: 'some_ip'
container_name: 'some_name'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://some_ip'
gitlab_rails['gitlab_shell_ssh_port'] = 4381
nginx['redirect_http_to_https'] = true
nginx['redirect_http_to_https_port'] = 80
ports:
- '6312:443'
- '4381:22'
volumes:
- '/srv/gitlab/config:/etc/gitlab'
- '/srv/gitlab/logs:/var/log/gitlab'
- '/srv/gitlab/data:/var/opt/gitlab'
When accessing https://some_ip:6312 it works fine, but for some_ip:6312 it displays:
400 Bad Request The plain HTTP request was sent to HTTPS port nginx
The reason is obvious, but how to get around this? Must I set ssl off for nginx, if so, how do I do that for the Docker image?
I've tried different combinations of adding the following lines, but no success:
nginx['redirect_http_to_https'] = true
nginx['redirect_http_to_https_port'] = 80
gitlab_rails['gitlab_https'] = false
gitlab_rails['gitlab_port'] = 443
nginx['ssl'] = 'off'
nginx['listen_port'] = 443
nginx['listen_https'] = false
EDIT:
In short: I want the user, who connects to the website via some_ip:6312 or http://some_ip:6312, to be redirected to https://some_ip:6312.
Its not possible to run http and https on the same port
https://askubuntu.com/questions/860511/is-it-possible-to-set-same-port-work-with-http-and-https
When you use https://domain/ the port is automatically assumed as 443 and in case of http://domain/ it is assumed as 80. So both of them actually run on different port.