2 Vaadin Apps 1 Traefik
The goal is to setup 2 Vaadin apps on one Ubuntu machine:
- 2 Vaadin apps are running in production mode in docker
- Configure Traefik as ‘reverse proxy’ so that the apps are accessible via
http://app1.myserver.fake
andhttp://app2.myserver.fake
Note: you can alternatively configure the Vaadin apps to run on
/app1
context root, then you can also publish the app at, say,http://myserver.fake/app1
.
Note: you might be tempted to try to configure path rewriting, to have the apps serving
/
context root to be published athttp://myserver.fake/app1
andhttp://myserver.fake/app2
, respectively. It’s not a good idea: see StackOverflow answer for details. In short, I don’t think this is possible (e.g. https://community.traefik.io/t/traefik-2-reverse-proxy-to-a-path/8623/12 ), and also I don’t think it’s a good idea. Remember that you would need to rewrite all links in the response html files; possibly session cookie paths. Rewriting response html is most probably not a good idea since it might not be possible to do so reliably (see Jenkins behind reverse proxy for more details).
Traefik Setup
I assume that docker is installed & configured on your machine. To run Traefik quickly, we’ll just run it according to
Traefik Quick Start. Create a docker-compose.yml
:
version: '3'
networks:
web:
external: true
services:
traefik:
# The official v3 Traefik docker image
image: traefik:v3.3.5
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
networks:
- web
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
Create a shared docker network named web
, which will be used by Traefik to access your Vaadin apps:
$ docker network create web
To start Traefik:
$ docker-compose up -d
Now browse to localhost and check that you can see the Traefik dashboard.
Faking the DNS addresses
Edit /etc/hosts
and add the following line to the end:
127.0.0.1 app1.myserver.fake app2.myserver.fake
Now when browsing to http://app1.myserver.fake
, the browser will report the hostname as app1.myserver.fake
,
exactly as if the DNS name was provided by an actual DNS server. We can take advantage of this,
to test as if on a real environment.
Alternatively setup a wildcard DNS rules.
Setting up Vaadin apps
We’ll run two Vaadin apps from docker: vaadin-boot-example-gradle and beverage-buddy-vok. To build docker images out of those apps, run the following in your terminal:
git clone https://github.com/mvysny/vaadin-boot-example-gradle
cd vaadin-boot-example-gradle
docker build --no-cache -t test/vaadin-boot-example-gradle:latest .
and
git clone https://github.com/mvysny/beverage-buddy-vok
cd beverage-buddy-vok
docker build --no-cache -t test/beverage-buddy-vok:latest .
Now, create a file named vaadin-boot-example-gradle.docker-compose.yml
:
version: '3'
networks:
web:
external: true
services:
vaadin-boot-example-gradle:
image: test/vaadin-boot-example-gradle:latest
networks:
- web
labels:
- "traefik.http.routers.vaadin-boot-example-gradle.entrypoints=http"
- "traefik.http.routers.vaadin-boot-example-gradle.rule=Host(`app1.myserver.fake`)"
Now, create a file named beverage-buddy-vok.docker-compose.yml
:
version: '3'
networks:
web:
external: true
services:
beverage-buddy-vok:
image: test/beverage-buddy-vok:latest
networks:
- web
labels:
- "traefik.http.routers.beverage-buddy-vok.entrypoints=http"
- "traefik.http.routers.beverage-buddy-vok.rule=Host(`app2.myserver.fake`)"
Run them:
$ docker-compose -f vaadin-boot-example-gradle.docker-compose.yml up -d
$ docker-compose -f beverage-buddy-vok.docker-compose.yml up -d
Traefik will automatically discover those docker containers and will setup proper routing - you can check out Traefik’s Dashboard (the HTTP tab, the HTTP routers sub-tab) to see that.
Verify that you can access those apps: app1.myserver.fake and app2.myserver.fake.
https
You can enable https in Traefik very easily. Traefik will generate and use self-signed certificates by default.
To enable https, modify Traefik docker-compose.yaml
as follows:
version: '3'
networks:
web:
external: true
services:
traefik:
# The official v3 Traefik docker image
image: traefik:v3.3.5
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker --entrypoints.https.address=:443
networks:
- web
ports:
# The Web UI (enabled by --api.insecure=true)
- "8080:8080"
# The 'https' entrypoint
- "443:443"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
Modify the apps’ docker-compose.yml
as follows:
...
labels:
- "traefik.http.routers.vaadin-boot-example-gradle.entrypoints=https"
- "traefik.http.routers.vaadin-boot-example-gradle.tls=true"
- "traefik.http.routers.vaadin-boot-example-gradle.rule=Host(`app1.myserver.fake`)"
Serving both http and https
You need to enable the http interface again, by adding --entrypoints.http.address=:80
(and open Docker container port: - "80:80"
).
Since one router can’t serve both http and https (since the tls
setting can not be both true
and false
),
we need to create additional router:
labels:
- "traefik.http.routers.vaadin-boot-example-gradle.entrypoints=https"
- "traefik.http.routers.vaadin-boot-example-gradle.tls=true"
- "traefik.http.routers.vaadin-boot-example-gradle.rule=Host(`app1.myserver.fake`)"
- "traefik.http.routers.vaadin-boot-example-gradle_http.entrypoints=http"
- "traefik.http.routers.vaadin-boot-example-gradle_http.rule=Host(`app1.myserver.fake`)"
https via Let’s Encrypt
See Setup wildcard DNS https certificates on Traefik with GoDaddy and Let’s Encrypt.
Securing Things via Multiple Networks, plus running apps via pure docker
At the moment, all apps run on the same network web
, which is potentially a security issue.
The easiest way is to create one network per app, isolating the apps from each other:
$ docker network create web1
$ docker network create web2
$ docker network connect web1 CONTAINER_ID_OF_TRAEFIK
$ docker network connect web2 CONTAINER_ID_OF_TRAEFIK
Obtain the Traefik container id by running docker ps
.
Kill & remove the vaadin-boot-example-gradle
and beverage-buddy-vok
docker containers
via docker kill
and docker container rm
, so that we can start those two via pure docker:
$ docker run -d --network web1 --name vaadin-boot-example-gradle \
--label "traefik.http.routers.vaadin-boot-example-gradle.entrypoints=http" \
--label "traefik.http.routers.vaadin-boot-example-gradle.rule=Host(`app1.myserver.fake`)" \
test/vaadin-boot-example-gradle:latest
$ docker run -d --network web2 --name beverage-buddy-vok \
--label "traefik.http.routers.beverage-buddy-vok.entrypoints=http" \
--label "traefik.http.routers.beverage-buddy-vok.rule=Host(`app2.myserver.fake`)" \
test/beverage-buddy-vok:latest
Observe that Traefik automatically registered both apps exactly as before.
Hitting the network limit
By default you can create 29 docker networks and then docker will fail with
Error response from daemon: failed to parse pool request for address space "LocalDefault" pool "" subpool "": could not find an available predefined netw
ork
.
To be able to create more networks, edit /etc/docker/daemon.json
and add:
{
"default-address-pools": [
{
"base":"172.17.0.0/12",
"size":16
},
{
"base":"192.168.0.0/16",
"size":20
},
{
"base":"10.99.0.0/16",
"size":24
}
]
}
then sudo service docker restart
. Taken from Stack Overflow.