Traefik with 2 different services on the same domain

What I would like to do

I'm trying to understand how to add 2 different services with Traefik on the same virtual server with Docker Compose. I have chosen a java / tomcat server and a php / apache server but you can choose 2 different services.

What I would like to achieve

I would like to view the content of my website in java on https://java.localhost and the content of my website in php on https://php.localhost.
Both websites projected individually with Traefik work.

What I get

When I try to put the 2 services on the same virtual server, on the browser I get '404 page not found'. In the Ubuntu shell I get the following code:

Creating container-java-eb    ... done
Creating container-php-eb     ... done
Attaching to container-java-eb, container-traefik-eb, container-php-eb
container-php-eb | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.30.0.4. Set the 'ServerName' directive globally to suppress this message
container-php-eb | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.30.0.4. Set the 'ServerName' directive globally to suppress this message
container-php-eb | [Mon Jul 11 14:14:14.942848 2022] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.53 (Debian) PHP/8.1.8 configured -- resuming normal operations
container-php-eb | [Mon Jul 11 14:14:14.942939 2022] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
container-traefik-eb | time="2022-07-11T14:14:15Z" level=info msg="Configuration loaded from flags."
container-java-eb | 
container-java-eb |   .   ____          _            __ _ _
container-java-eb |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
container-java-eb | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
container-java-eb |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
container-java-eb |   '  |____| .__|_| |_|_| |_\__, | / / / /
container-java-eb |  =========|_|==============|___/=/_/_/_/
container-java-eb |  :: Spring Boot ::                (v2.7.1)
container-java-eb | 
container-java-eb | 2022-07-11 14:14:16.794  INFO 1 --- [           main] springbootdemo.Application               : Starting Application v0.0.1 using Java 11.0.15 on e0a6fc7ff3f1 with PID 1 (/appfolder/spring-boot-jar-docker-demo-(http).jar started by root in /appfolder)
container-java-eb | 2022-07-11 14:14:16.804  INFO 1 --- [           main] springbootdemo.Application               : No active profile set, falling back to 1 default profile: "default"
container-java-eb | 2022-07-11 14:14:19.024  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
container-java-eb | 2022-07-11 14:14:19.036  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
container-java-eb | 2022-07-11 14:14:19.037  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.64]
container-java-eb | 2022-07-11 14:14:19.138  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
container-java-eb | 2022-07-11 14:14:19.139  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2179 ms
container-java-eb | 2022-07-11 14:14:19.903  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
container-java-eb | 2022-07-11 14:14:19.920  INFO 1 --- [           main] springbootdemo.Application               : Started Application in 4.168 seconds (JVM running for 5.869)

My Docker Compose code

docker-compose.yml

version: "3.9"

services:
  traefik:
    build: ./traefik
    image: image-traefik-eb:v.1.0
    container_name: container-traefik-eb
    command:
      - --log.level=INFO
      - --log.filePath=/data-log/traefik.log
      - --log.format=json
      - --api.insecure
      - --api.dashboard
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certresolver=leresolver
      - --entrypoints.websecure.http.tls.domains.main=localhost
      - --entrypoints.websecure.http.tls.domains.sans=*.localhost
      - --certificatesresolvers.leresolver.acme.tlsChallenge=true
      - --certificatesresolvers.leresolver.acme.email=localhost@gmail.com
      - --certificatesresolvers.leresolver.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
      - --certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json
      - --log.filePath=/traefik-log/traefik.log
      - --log.format=json
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./volumes/data-letsencrypt/:/letsencrypt
      - ./volumes/data-log/:/data-log/
    ports:
      - 8080:8080
      - 80:80
      - 443:443
      
  java:
    build: ./java
    image: image-java-eb:v.1.0
    container_name: container-java-eb
    labels:
      traefik.enable: 'true'
      traefik.http.routers.training.rule: Host(`java.localhost`)
      traefik.http.routers.training.tls.certresolver: leresolver
    volumes:
      - ./volumes/data-java:/appfolder
    restart: on-failure

  php:
    build: ./php-apache
    image: image-php-eb:v.1.0
    container_name: container-php-eb
    labels:
      traefik.enable: 'true'
      traefik.http.routers.training.rule: Host(`php.localhost`)
      traefik.http.routers.training.tls.certresolver: leresolver
    volumes:
      - ./volumes/data-php:/var/www/html
    restart: on-failure

index.php

<!doctype html>
<html lang="it">
<head><title>Ciao Mondo!</title></head>
<body>
<h1>Ciao Mondo!</h1>
<p>Questa &egrave; una semplice pagina PHP.</p>
<h2>Versione di PHP in uso:</h2>
<?php phpinfo(); ?>
</body>
</html>

Dockerfile

FROM php:8.1-apache

Hello @Milano2022,

you have to use different router names for each service in the same docker-compose file.
like:
... traefik.http.routers.training1.rule: Host(java.localhost)
... traefik.http.routers.training2.rule: Host(php.localhost)

Hopefully this helps :slight_smile:

Greetings,
Julian

1 Like

Thanks a lot @oJay! Magnificent! Excellent! Stupendous!

WAWWWWW!!!!!!

Problem solved.
I also found other errors.
Why doesn't this code work locally? Does the code only work on a real domain?

      - --entrypoints.websecure.http.tls.domains.main=localhost
      - --entrypoints.websecure.http.tls.domains.sans=*.localhost

Why can't I get the log file? Where am I wrong?

      - --log.filePath=/data-log/traefik.log
      - --log.format=json
    volumes:
      - ./volumes/data-log/:/data-log/

I have removed the strings but I would like to have a wildcard certificate and read the logs, especially in development.

I don't set a file and use docker logs or configure docker to send to a remote log server.
If you want access logs --accesslog=true and I'd recommend --accesslog.format=json

Yes. Its for letsencrypt so it has to be real domains. Wildcards for letsencrypt are only supported by DNS01 challenge.

1 Like

A thousand thanks. With your code I was able to see the log file. The let's encrypt certificate is not produced and I get this error:

{"level":"info","msg":"Traefik version 2.8.0 built on 2022-06-29T15:43:58Z","time":"2022-07-14T12:06:50Z"}
{"level":"info","msg":"\nStats collection is disabled.\nHelp us improve Traefik by turning this feature on :)\nMore details on: https://doc.traefik.io/traefik/contributing/data-collection/\n","time":"2022-07-14T12:06:50Z"}
{"level":"warning","msg":"Traefik Pilot is deprecated and will be removed soon. Please check our Blog for migration instructions later this year.","time":"2022-07-14T12:06:50Z"}
{"level":"info","msg":"Starting provider aggregator aggregator.ProviderAggregator","time":"2022-07-14T12:06:50Z"}
{"level":"info","msg":"Starting provider *traefik.Provider","time":"2022-07-14T12:06:50Z"}
{"level":"info","msg":"Starting provider *docker.Provider","time":"2022-07-14T12:06:50Z"}
{"level":"info","msg":"Starting provider *acme.ChallengeTLSALPN","time":"2022-07-14T12:06:50Z"}
{"level":"info","msg":"Starting provider *acme.Provider","time":"2022-07-14T12:06:50Z"}
{"ACME CA":"https://acme-v02.api.letsencrypt.org/directory","level":"info","msg":"Testing certificate renew...","providerName":"leresolver.acme","time":"2022-07-14T12:06:50Z"}
{"ACME CA":"https://acme-v02.api.letsencrypt.org/directory","level":"warning","msg":"The domain { []} is duplicated in the configuration but will be process by ACME provider only once.","providerName":"leresolver.acme","routerName":"websecure-training1@docker","rule":"Host(`www.real-domain.ml`)","time":"2022-07-14T12:06:51Z"}
{"level":"error","msg":"Unable to obtain ACME certificate for domains \"\" : unable to generate a certificate in ACME provider when no domain is given","providerName":"leresolver.acme","time":"2022-07-14T12:06:51Z"}

I don't understand this sentence:

What should I add to my code?

I have no problems locally but on the real server I have a few more problems. I also noticed another serious problem. Suppose we have only one service (php) and write the following code:

version: "3.9"

services:
  traefik:
    build: ./traefik
    image: image-traefik-eb:v.1.0
    container_name: container-traefik-eb
    command:
      - --log.level=INFO
      - --log.filePath=/data-log/traefik.log
      - --log.format=json
      - --accesslog=true
      - --api.insecure
      - --api.dashboard
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certresolver=leresolver
      - --certificatesresolvers.leresolver.acme.tlsChallenge=true
      - --certificatesresolvers.leresolver.acme.email=myemail@gmail.com
      - --certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./volumes/data-letsencrypt/:/letsencrypt
      - ./volumes/data-log/:/data-log/
    ports:
      - 80:80
      - 443:443

  php:
    build: ./php-apache
    image: image-php-apache-eb:v.1.0
    container_name: container-php-apache-eb
    labels:
      traefik.enable: 'true'
      traefik.http.routers.training1.rule: Host(`www.mydomain.ml`)
    volumes:
      - ./volumes/data-php:/var/www/html
    restart: on-failure

This is what happens:

https://www.mydomain.ml/ > OK! > I read the html file and get a valid certificate
http://www.mydomain.ml/ > OK! > I am sent back to https://www.mydomain.ml/
https://mydomain.ml/ > ERROR! > 404 page not found
http://mydomain.ml/ > OK! > I am sent back to https://mydomain.ml/ > 404 page not found

The code works but needs to be perfected.

I found an interesting page but I don't know how to translate the post code of the format I use. I believe I need a solution like the one below. Google.it also uses this setting. Traefik.io uses the opposite redirect and I like it less but they are both valid. My current setup certainly isn't.

version: "3.9"

services:
  traefik:
    build: ./traefik
    image: image-traefik-eb:v.1.0
    container_name: container-traefik-eb
    command:
      - --log.level=INFO
      - --log.filePath=/data-log/traefik.log
      - --log.format=json
      - --accesslog=true
      - --api.insecure
      - --api.dashboard
      - --providers.docker
      - --providers.docker.exposedbydefault=false
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entrypoint.scheme=https
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certresolver=leresolver
      - --certificatesresolvers.leresolver.acme.tlsChallenge=true
      - --certificatesresolvers.leresolver.acme.email=*****************@gmail.com
      - --certificatesresolvers.leresolver.acme.storage=/letsencrypt/acme.json
      - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.permanent=true
      - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.regex="^https?://(?:www\\.)?(.+)"
      - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.replacement="https://www.${1}"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./volumes/data-letsencrypt/:/letsencrypt
      - ./volumes/data-log/:/data-log/
    ports:
      - 80:80
      - 443:443

  php:
    build: ./php-apache
    image: image-php-apache-eb:v.1.0
    container_name: container-php-apache-eb
    labels:
      traefik.enable: 'true'
      traefik.http.routers.training.rule: Host(`www.*************************.ml`)
      traefik.http.routers.training.middlewares: redirect-non-www-to-www@file
    volumes:
      - ./volumes/data-php:/var/www/html
    restart: on-failure

Host(`www.mydomain.ml`,`mydomain.ml`)
Is one way.

1 Like

Works! Magnificent! I have no more error messages!

The problem is that all sites use one domain, not both, most use www.something.ml and not something.ml.

Why don't the codes I find on the various sites work?

      - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.permanent=true
      - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.regex="^https?://(?:www\\.)?(.+)"
      - --entrypoints.websecure.http.middlewares.redirect-non-www-to-www.redirectregex.replacement="https://www.${1}"
      traefik.http.routers.training.middlewares: redirect-non-www-to-www@file

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.