Vert.x redirect http to https
The final solutions I came up with are shown below and they are equivalent. The idea in both cases is to have an http server (that listens on port 80 of course) that redirects every call to an https server.
So in my case I can do exactly what I want because http://mydomain.it is redirected to https://mydomain.it as expected. For example when I make a call to
http://mydomain.it/api/polynomial/laguerre
There is an http server alive that receives the request but then it throws the ball immediately to
https://mydomain.it/api/polynomial/laguerre
Of course if you directly call the https version this "intermediate" step does not happen.
Using Vert.x
The answer from Hugo in the above post gives a valid solution using Vertx. I have a main verticle that looks like this:
public class MainVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
//Deploy the HTTPS server
vertx.deployVerticle(
"com.albertomiola.equations.http.HttpsServerVerticle",
new DeploymentOptions().setInstances(n)
);
//Deploy the HTTP server
vertx.deployVerticle(
"com.albertomiola.equations.http.HttpServerVerticle",
new DeploymentOptions().setInstances(1)
);
}
}
The first verticle is the "real" website because it contains all the logic that I need in my webservice (routers, handlers, models...) and it looks like this:
public class HttpsServerVerticle extends AbstractVerticle {
@Override
public void start(Promise<Void> startPromise) throws Exception {
// Setup the HTTPS
var httpOptions = new HttpServerOptions()
.setCompressionSupported(true)
.setPort(443)
.setSsl(true)
.setPemTrustOptions(...)
.setPemKeyCertOptions(...);
// Start the server and the routes
var server = vertx.createHttpServer(httpOptions);
var router = Router.router(vertx);
//Start
server
.requestHandler(router)
.listen(ar -> {
if (ar.succeeded()) {
startPromise.complete();
} else {
startPromise.fail(ar.cause());
}
});
}
}
The other verticle instead is just an http server that permanently redirects (with the 301) to the https version of the webserver. Here's the code:
public class HttpsServerVerticle extends AbstractVerticle {
@Override
public void start(Promise<Void> startPromise) throws Exception {
var server = vertx.createHttpServer(httpOptions);
var router = Router.router(vertx);
//Start
server
.requestHandler(r -> {
r.response()
.setStatusCode(301)
.putHeader("Location", r.absoluteURI().replace("http", "https"))
.end();
});
}
}
In this way there are 2 servers active but actually it's like if there were only 1 because the http server (port 80) redirects every call to the https server (port 443).
Using Nginx
The other approach that I have tested requires nginx but it does the same things that I've done in the above example. It listens to http requests on port 80 and then it redirects them to the https version.
- Install Nginx on my Ubuntu server (or whatever you have)
- Go in the configuration file which is in
/etc/nginx/nginx.conf
in my case Add the below code
http { server { listen 80; server_name mydomain.it; return 301 https://$server_name$request_uri; } //other code... }
- Restart with
systemctl restart nginx
- Restart with
Now every call to the http version is redirected to the https version. Thanks to the user injecteer which has suggested me this way.
I am using this approach because I prefer not having a single verticle only for the http version. Also this article from the Vertx website says that this approach is valid:
It is common to expose HTTP servers in production through a front HTTP server / proxy like Nginx, and have it use HTTPS for incoming connections. Vert.x can also expose HTTPS by itself, so as to provide end-to-end encryption.
So yeah, setup https with Vertx (I'd recommend letsencrypt certifies) but also redirect calls to https with nginx.
I wrongly thought that I could do something particular with Vertx to handle this redirect but that's not possible. After the suggestions of the people in this answer AND some good googling around I've learned that this approach is common and that's what I should do!