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.

  1. Install Nginx on my Ubuntu server (or whatever you have)
  2. Go in the configuration file which is in /etc/nginx/nginx.conf in my case
  3. Add the below code

    http {
        server {
                listen         80;
                server_name    mydomain.it;
                return         301 https://$server_name$request_uri;
        }
    
        //other code...
    }
    
    1. Restart with systemctl restart nginx

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!