I have a docker compose file, I want to host my container on example.com:8080 and api.example.com:443, I can accomplish that goal right now.
However I don't want 2 seperate service for that, I want to eliminate either my_api or abcxyz and have 1 service only and accomplish the same behavior, i.e. my container should be hosted at example.com:8080 and not on example.com:443 AND api.example.com:443 but not on api.example.com:8080
Is there a way to do it under 1 service.
version: "3"
services:
traefik:
image: traefik
command:
- --api.dashboard=false
- --api.insecure=false
- --providers.docker
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=web-secure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true
- --entrypoints.web-secure.address=:443
- --entrypoints.spiderman.address=:8080
- --providers.file.directory=/configuration/
- --providers.file.watch=true
ports:
- 80:80
- 443:443
- 8080:8080
volumes:
- ./certificates.yml:/configuration/certificates.yml:ro
- /etc/letsencrypt:/letsencrypt:ro
- /var/run/docker.sock:/var/run/docker.sock
my_api:
image: traefik/whoami
deploy:
replicas: 5
labels:
- "traefik.http.routers.my_api.entrypoints=spiderman"
- "traefik.http.routers.my_api.rule=Host(`example.com`)"
- "traefik.http.routers.my_api.tls=true"
abcxyz:
image: traefik/whoami
deploy:
replicas: 5
labels:
- "traefik.http.routers.abcxyz.entrypoints=web-secure"
- "traefik.http.routers.abcxyz.rule=Host(`api.example.com`)"
- "traefik.http.routers.abcxyz.tls=true"
I could do -
labels:
- "traefik.http.routers.my_api.entrypoints=spiderman,web-secure"
- "traefik.http.routers.my_api.rule=Host(`example.com`,`api.example.com`)"
- "traefik.http.routers.my_api.tls=true"
but it would also serve at example.com:443 which I don't want because i want to host my cool wordpress site there! :)
I think you're looking for something like this:
services:
traefik:
image: traefik
command:
- --api.dashboard=false
- --api.insecure=false
- --providers.docker
- --entrypoints.web.address=:80
- --entrypoints.web.http.redirections.entrypoint.to=web-secure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true
- --entrypoints.web-secure.address=:443
- --entrypoints.spiderman.address=:8080
ports:
- 127.0.0.3:80:80
- 127.0.0.3:443:443
- 127.0.0.3:8080:8080
volumes:
- /run/docker.sock:/run/docker.sock
my_api:
image: traefik/whoami
hostname: my_api
labels:
- traefik.enable=true
- traefik.http.routers.example_com.entrypoints=spiderman
- traefik.http.routers.example_com.rule=Host(`example.com`)
- traefik.http.routers.example_com.service=my_api
- traefik.http.routers.example_com.tls=true
- traefik.http.routers.my_api.entrypoints=web-secure
- traefik.http.routers.my_api.rule=Host(`api.example.com`)
- traefik.http.routers.my_api.tls=true
- traefik.http.services.my_api.loadBalancer.server.port=80
Note that here I've bound everything to local address 127.0.0.3 for testing, but of course that's not necessary; I did that to avoid conflicts with existing services I have listening on ports 80, 443, and 8080.
Testing
I've defined this shell function that ensures the various hostname:port combinations resolve correctly (you could edit /etc/hosts instead to accomplish the same thing) and shows the HTTP status code for each request:
fetch() {
curl -sf \
--resolve api.example.com:443:127.0.0.3 \
--resolve api.example.com:8080:127.0.0.3 \
--resolve example.com:443:127.0.0.3 \
--resolve example.com:8080:127.0.0.3 \
-k -w '%{stderr}%{http_code}\n' $1
}
Using that, let's test our your various requirements.
my container should be hosted at example.com:8080
$ fetch https://example.com:8080 | grep -i host
200
Hostname: my_api
Host: example.com:8080
X-Forwarded-Host: example.com:8081
and not on example.com:443
$ fetch https://example.com:443 | grep -i host
404
AND api.example.com:443
$ fetch https://api.example.com:443 | grep -i host
200
Hostname: my_api
Host: api.example.com
X-Forwarded-Host: api.example.com
but not on api.example.com:8080
$ fetch https://api.example.com:8080 | grep -i host
404
I think that covers your requirements!
Related
I'm new to Traefik and have following basic question. Traefik should proxy NGINX. My goal is to start the stack either with http (f.e. locally) or with https (production): Therefore I've split the docker config in two yml files:
docker-compose-https.yml
version: "3.3"
services:
traefik:
image: "traefik:v2.4"
container_name: "traefik"
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=my#email.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
docker-compose.yml
nginx:
image: nginx:alpine
ports:
- 80:80
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host('test.example.com')"
- "traefik.http.routers.nginx.entrypoints=websecure"
- "traefik.http.routers.nginx.tls.certresolver=myresolver"
This works so far. If I run docker-compose up -d with -f docker-compose-ssl.yml trafik jumps in for https and issues a cert. Without using it I can still start nginx over http. Unfortuantely what is not working is, as soon as Traefik is up it does not redirect http to https as my config should ask for. What do I oversee?
You need to use the RedirectScheme for the redirection from http to https and the middleware to the router as mentioned in https://doc.traefik.io/traefik/middlewares/overview/#configuration-example
So, your docker-compose.yml should look like this
nginx:
image: nginx:alpine
ports:
- 80:80
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.entrypoints=web"
- "traefik.http.routers.nginx.rule=Host(`test.example.com`)"
- "traefik.http.middlewares.nginx-redirectscheme.redirectscheme.scheme=https"
- "traefik.http.routers.nginx.middlewares=nginx-redirectscheme"
- "traefik.http.routers.nginx-secured.entrypoints=websecure"
- "traefik.http.routers.nginx-secured.rule=Host(`test.example.com`)"
- "traefik.http.routers.nginx-secured.tls=true"
- "traefik.http.routers.nginx-secured.tls.certresolver=myresolver"
I want use traefik2.0 publish port 80 and 7000, the port 7000 is for frp(TCP). Now i am testing locally with 2.0 doc, i am using example on quick start but not running.
This is my docker compose file.
version: '3'
services:
reverse-proxy:
image: traefik:v2.0 # The official v2.0 Traefik docker image
command:
- "--api"
- "--entrypoints='Name:http Address::80'"
- "--providers.docker" # Enables the web UI and tells Traefik to listen to docker
- "--providers.docker.swarmmode=true"
- "--providers.docker.watch=true"
ports:
- "80:80" # The HTTP port
- "8080:8080" # The Web UI (enabled by --api)
networks:
- traefik-net
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
labels:
- traefik.enable=false
volumes:
- /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events
whoami:
image: containous/whoami # A container that exposes an API to show its IP address
networks:
- traefik-net
deploy:
labels:
- "traefik.http.routers.whoami.tls=true"
- "traefik.http.routers.whoami.entrypoints=https"
- "traefik.http.routers.whoami.rule=Host(`whoami.domain.com`)"
- "traefik.http.middlewares.whoami.redirectscheme.scheme=https"
networks:
traefik-net:
external: true
i expect which labels used on traefik2.0 can work
You're almost there!
Replace
- "--entrypoints='Name:http Address::80'"
with
- "--entryPoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
Enable the dashboard in a non-production environment. You'll also need to replace
- "--api" with
- "--api.insecure=true"
One of the labels of whoami has a mistake. There is no https entrypoint, it's now called websecure. So change
- "traefik.http.routers.whoami.entrypoints=https"
with
- "traefik.http.routers.whoami.entrypoints=websecure"
And finally expose the internal port that the whoami app is running on.
By adding this to the label of whoami
- traefik.http.services.whoami-service.loadbalancer.server.port=80
You should be able to verify it using the traefik dashboard on localhost:8080
I asked a question here and got part of my problem solved, but I was advised to create another question because it started to get a bit lengthy in the comments.
I'm trying to use docker to run multiple PHP,MySQL & Apache based apps on my Mac, all of which would use different docker-compose.yml files (more details in the post I linked). I have quite a few repositories, some of which communicate with one another, and not all of them are the same PHP version. Because of this, I don't think it's wise for me to cram 20+ separate repositories into one single docker-compose.yml file. I'd like to have separate docker-compose.yml files for each repository and I want to be able to use an /etc/hosts entry for each app so that I don't have to specify the port. Ex: I would access 2 different repositories such as http://dockertest.com and http://dockertest2.com (using /etc/hosts entries), rather than having to specify the port like http://dockertest.com:8080 and http://dockertest.com:8081.
Using the accepted answer from my other post I was able to get one app running at a time (one docker-compose.yml file), but if I try to launch another with docker-compose up -d it results in an error because port 80 is already taken. How can I runn multiple docker apps at the same time, each with their own docker-compose.yml files and without having to specify the port in the url?
Here's a docker-compose.yml file for the app I made. In my /etc/hosts I have 127.0.0.1 dockertest.com
version: "3.3"
services:
php:
build: './php/'
networks:
- backend
volumes:
- ./public_html/:/var/www/html/
apache:
build: './apache/'
depends_on:
- php
- mysql
networks:
- frontend
- backend
volumes:
- ./public_html/:/var/www/html/
environment:
- VIRTUAL_HOST=dockertest.com
mysql:
image: mysql:5.6.40
networks:
- backend
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
nginx-proxy:
image: jwilder/nginx-proxy
networks:
- backend
ports:
- 80:80
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
frontend:
backend:
I would suggest to extract the nginx-proxy to a separate docker-compose.yml and create a repository for the "reverse proxy" configuration with the following:
A file with extra contents to add to /etc/hosts
127.0.0.1 dockertest.com
127.0.0.1 anothertest.com
127.0.0.1 third-domain.net
And a docker-compose.yml which will have only the reverse proxy
version: "3.3"
services:
nginx-proxy:
image: jwilder/nginx-proxy
ports:
- 80:80
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
Next, as you already mentioned, create a docker-compose.yml for each of your repositories that act as web endpoints. You will need to add VIRTUAL_HOST env var to the services that serve your applications (eg. Apache).
The nginx-proxy container can run in "permanent mode", as it has a small footprint. This way whenever you start a new container with VIRTUAL_HOST env var, the configuration of nginx-proxy will be automatically updated to include the new local domain. (You will still have to update /etc/hosts with the new entry).
If you decide to use networks, your web endpoint containers will have to be in the same network as nginx-proxy, so your docker-compose files will have to be modified similar to this:
# nginx-proxy/docker-compose.yml
version: "3.3"
services:
nginx-proxy:
image: jwilder/nginx-proxy
ports:
- 80:80
networks:
- reverse-proxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:
reverse-proxy:
# service1/docker-compose.yml
version: "3.3"
services:
php1:
...
networks:
- backend1
apache1:
...
networks:
- nginx-proxy_reverse-proxy
- backend1
environment:
- VIRTUAL_HOST=dockertest.com
mysql1:
...
networks:
- backend1
networks:
backend1:
nginx-proxy_reverse-proxy:
external: true
# service2/docker-compose.yml
version: "3.3"
services:
php2:
...
networks:
- backend2
apache2:
...
networks:
- nginx-proxy_reverse-proxy
- backend2
environment:
- VIRTUAL_HOST=anothertest.com
mysql2:
...
networks:
- backend2
networks:
backend2:
nginx-proxy_reverse-proxy:
external: true
The reverse-proxy network that is created in nginx-proxy/docker-compose.yml is referred as nginx-proxy_reverse-proxy in the other docker-compose files because whenever you define a network - its final name will be {{folder name}}_{{network name}}
If you want to have a look at a solution that relies on browser proxy extension instead of /etc/hosts, check out mitm-proxy-nginx-companion
Okay, so I've got a node-js app I'd like to access thru traefik.
The node-js app runs on port 3000
I've got traefik running after following the test-it instructions from the getting started page.
docker-compose.yml
version: '2'
services:
app:
build:
context: .
dockerfile: docker/app/Dockerfile
environment:
- NODE_ENV=development
- NODE_PORT=3000
volumes:
- ./app:/app
expose:
- "3000"
networks:
- web
labels:
- "traefik.backend=microservice"
- "traefik.backend.port=3000"
- "traefik.port=3000"
- "traefik.frontend.rule=Host:microservice.docker.localhost"
networks:
web:
external:
name: traefik_webgateway
Trying to connect:
curl -H Host:microservice.docker.localhost http://localhost/
Bad Gateway
curl -H Host:microservice.docker.localhost http://localhost:3000/
curl: (52) Empty reply from server
But curl -H Host:whoami.docker.localhost http://localhost/ works like intended.
The problem was that my microservice was bound to listen to localhost:3000 instead I changed it to 0.0.0.0:3000 and it worked like a charm.
removed - "traefik.backend.port=3000" from the docker-compose.yml
added 127.0.0.1 microservice.docker.localhost to /etc/hosts
which rendered me able to:
curl http://microservice.docker.localhost/ and get the response I was expecting
I'm a microservice!
I have a Traefik reverse proxy which generate ACME certificate and I would like to have SSL enabled on my docker container.
In my container I have a self-signed certificate but Traefik refuse to connect to it.
My docker-compose.yml:
version: "2"
services:
magento:
image: lavoweb/php-5.6
expose:
- 80
- 443
volumes:
- ./data/src/:/var/www/html
labels:
- "traefik.port=80"
- "traefik.backend=swarm"
- "traefik.protocol=https"
- "traefik.frontend.rule=Host:1.swarm.lavoweb.net"
- "traefik.docker.network=web"
networks:
- web
- internal
networks:
web:
external:
name: web
internal:
driver: bridge
I got this error:
Internal Server Error
This is how I've managed to get this working with the LetsEncrypt automated renewal using Docker Swarm and Docker Compose V3:
version: '3'
services:
traefik:
image: traefik
command: --web --docker --docker.domain=docker.localhost --docker.watch \
--logLevel=DEBUG \
--defaultEntryPoints='http,https' \
--entryPoints='Name:http Address::80' \
--entryPoints='Name:https Address::443 TLS' \
--docker.swarmmode=true \
--docker.exposedbydefault=false \
--acme \
--acme.entryPoint='https' \
--acme.email='sugarcane#gmail.com' \
--acme.ondemand=false \
--acme.acmelogging=true \
--acme.onhostrule=true \
--acme.storage='/etc/traefik/acme/acme.json'
networks:
- default
- traefik-net
ports:
- "80:80"
- "8080:8080"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- traefikdata:/etc/traefik/acme
mytestservice:
image: blah/mytestservice
networks:
- default
- traefik-net
ports:
- "8001:80"
deploy:
labels:
- "traefik.port=80"
- "traefik.enable=true"
- "traefik.backend=machine-mytestservice"
- "traefik.docker.network=traefik-net"
- "traefik.frontend.rule=Host:mydomain.com,www.mydomain.com"
networks:
traefik-net:
volumes:
traefikdata: