2 Vaadin Apps 1 Nginx
The goal is to setup 2 Vaadin apps on one Ubuntu machine:
- 2 Vaadin apps are running in production mode in docker
- Configure nginx as ‘reverse proxy’ so that the apps are accessible via
http://myserver.fake/app1
andhttp://myserver.fake/app2
, but alsohttp://vaadin1.fake
andhttp://vaadin2.fake
- We’ll make sure that the session cookies are changed properly, so that both apps are accessible at the same time.
Setup
I assume that docker is installed & configured on your machine. To install nginx, run:
sudo apt install nginx
Now browse to localhost and check that you can see the “Welcome to nginx!” welcome message.
The file is served from /var/www/html/index.nginx-debian.html
via the rule present in the /etc/nginx/sites-enabled/default
file.
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 .
docker run --rm -ti -p127.0.0.1:30000:8080 test/vaadin-boot-example-gradle
and
git clone https://github.com/mvysny/beverage-buddy-vok
cd beverage-buddy-vok
docker build --no-cache -t test/beverage-buddy-vok:latest .
docker run --rm -ti -p127.0.0.1:30001:8080 test/beverage-buddy-vok
Verify that you can access those apps: localhost:30000 and localhost:30001.
Notice something strange when you open both at the same time in two tabs: clicking into first app will make the other
one reload and vice versa. The problem is the session cookie which identifies the session:
it is bound to localhost host and /
path but not to a port, and therefore the apps keep overwriting
each other session cookies. You can see that for yourself, by opening dev tools in your Firefox via F12
,
then ‘Storage’ tab, ‘Cookies’ and the JSESSIONID
cookie. Notice how the value changes when you start
interacting with the other app.
We will fix that in nginx.
Faking the DNS addresses
Edit /etc/hosts
and add the following line to the end:
127.0.0.1 myserver.fake vaadin1.fake vaadin2.fake
Now when browsing to http://myserver.fake
, the browser will report the hostname as 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.
nginx reverse proxy
Nginx (pronounced Engine-X) is a web server offering lots of features.
We’ll use the ‘reverse proxy’ feature, which forwards all requests made to http://myserver.fake/app1
to http://localhost:30000
, then modify the response html (rewrites links and paths for example),
so that the browser thinks it came from http://myserver.fake/app1
.
Nginx is configured via the /etc/nginx/nginx.conf
file, which includes /etc/nginx/sites-enabled/*
and
/etc/nginx/conf.d/*.conf
. Let’s create /etc/nginx/conf.d/vaadin.conf
with the following contents:
server {
server_name myserver.fake;
location /app1/ {
proxy_pass http://localhost:30000/;
proxy_cookie_path / /app1/;
proxy_cookie_domain localhost $host;
}
}
Restart nginx via sudo systemctl reload nginx.service
and the first Vaadin app now runs
at myserver.fake/app1.
Note the proxy_cookie_path
and proxy_cookie_domain
. When you open http://myserver.fake/app1
in your browser, the request goes through nginx first. Nginx creates a completely new request
and sends it to the Vaadin app. Nginx will basically open http://localhost:30000/
, which means that
the path is /
and the host is localhost
. Vaadin (or, rather, the servlet container, i.e. Jetty)
sees that the request came from localhost
and produces a JSESSIONID cookie targeted
to host localhost
and path /
.
If the proxy_cookie_path
and proxy_cookie_domain
rewrite rules would be missing from nginx config file,
the cookie would go through nginx unmodified and would be ignored by the browser (since
the request went to myserver.fake/app1
but the cookie says localhost
). The browser
would not send the cookie back in the next request, which would cause Jetty to create a new session,
and respond with localhost
cookie, which would then be ignored, and so on and so forth.
Try removing the proxy_*
settings temporarily for yourself, to see the outcome.
We’re now ready to prepare the final configuration file:
server {
server_name myserver.fake;
location /app1/ {
proxy_pass http://localhost:30000/;
proxy_cookie_path / /app1/;
proxy_cookie_domain localhost $host;
}
location /app2/ {
proxy_pass http://localhost:30001/;
proxy_cookie_path / /app2/;
proxy_cookie_domain localhost $host;
}
}
server {
server_name vaadin1.fake;
location / {
proxy_pass http://localhost:30000/;
proxy_cookie_domain localhost $host;
}
}
server {
server_name vaadin2.fake;
location / {
proxy_pass http://localhost:30001/;
proxy_cookie_domain localhost $host;
}
}
Now try all the following links:
https via Let’s Encrypt
To enable https with Let’s Encrypt, you obviously have to set up nginx on an actual server running somewhere in the internet; then you have to register a bunch of domains and make them point to the IP address where the server is running.
Use Let’s Encrypt and follow Certbot instructions.
The sudo certbot --nginx
command will modify all active nginx configuration files
referenced from /etc/nginx/nginx.conf
: it will enable https, will download certificates and store them locally,
and set up periodic refresh of the certificates.
You do not have to have any account at Let’s Encrypt: the only requirement is to own the DNS domain and to have it pointing to the server’s IP.
What’s next
Now that you understand how this basic setup works, we’ll do the same setup, but with Kubernetes. Stay tuned.