How do I serve https and http for Jetty from one port?

Trejkaz picture Trejkaz · Jun 25, 2012 · Viewed 13.6k times · Source

(I know it's a duplicate question but the original poster asked it for the wrong reason. I'm not implying that I'm asking it for the right reason, but let's see.)

We have a web service which runs on a non-standard port number. Even though users seem to be able to remember the port number, occasionally they type http: instead of https: by mistake. Someone is asking whether we can serve HTTP on that port and then redirect them to HTTPS on the same port. It sounds evil... I like the usability but it feels like maybe it should be the browser's job to do this?

The one solution I have seen was "write your own proxy in front of Jetty." This solution would work, but I don't think it would work well as I am not confident that I can write a proxy which is as efficient as Jetty itself. Plus, even if the proxy itself is efficient, all the data would still have to go an additional hop, which is guaranteed to slow down the traffic anyway.

Is there a better way than this? Perhaps Jetty itself has some place where the protocol detection logic could be wedged which would allow taking advantage of their speed while also removing the additional hop a proxy would introduce.

Answer

jmort253 picture jmort253 · Jun 25, 2012

Update: See this answer for instructions on how to redirect a single port to both an HTTPS and HTTP listener. If for whatever reason you don't use that solution, see below:

It isn't possible to pipe traffic from both http and https on the same port. Jetty uses two completely different connectors to bind to the secure and unsecure ports. In fact, every web server I've encountered binds the two protocols to two completely separate ports.

One thing I would suggest for usability's sake is to use default ports, which completely hides the port from the user. By default http uses port 80, and by default https uses port 443. So if you configure your connectors to run on port 80 and port 443 respectively, then your users don't have to type a port, and your development team doesn't have to handle including port numbers in absolute paths in HTML, CSS, JavaScript, and other resources.

Jetty is designed to be a standalone Web server, unlike older versions of Tomcat, which Apache suggests run behind the Apache HTTP server. Therefore, as long as you have no other HTTP server running, and using those ports so you cannot, you should be able to configure Jetty to run on the default ports without any problem. This comes from experience. We run Jetty precisely in this manner.

Finally, a protocol can be bound to more than one port. Thus, if you're currently running Jetty on ports 8080 for http and 8443 for https, you can leave those connectors active and add two more connectors for port 80 and port 443. This enabled backwards compatibility for the part of your app that is still using the port numbers and gives you time to walk this forward.

<!-- Legacy HTTP connector -->
<Call name="addConnector">
  <Arg>
      <New class="org.mortbay.jetty.nio.SelectChannelConnector">
        <Set name="host"><SystemProperty name="jetty.host" /></Set>
        <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
        <Set name="maxIdleTime">30000</Set>
        <Set name="Acceptors">2</Set>
        <Set name="statsOn">false</Set>
        <Set name="confidentialPort">8443</Set>
        <Set name="lowResourcesConnections">5000</Set>
        <Set name="lowResourcesMaxIdleTime">5000</Set>
      </New>
  </Arg>
</Call>
<!-- Second connector for http on port 80 -->
<Call name="addConnector">
  <Arg>
      <New class="org.mortbay.jetty.nio.SelectChannelConnector">
        <Set name="host"><SystemProperty name="jetty.host" /></Set>
        <Set name="port"><SystemProperty name="jetty.port" default="80"/></Set>
        <Set name="maxIdleTime">30000</Set>
        <Set name="Acceptors">2</Set>
        <Set name="statsOn">false</Set>
        <Set name="confidentialPort">8443</Set>
        <Set name="lowResourcesConnections">5000</Set>
        <Set name="lowResourcesMaxIdleTime">5000</Set>
      </New>
  </Arg>
</Call>

<!-- Legacy SSL Connector for https port 8443 -->
<Call name="addConnector">
 <Arg>
  <New class="org.mortbay.jetty.security.SslSocketConnector">
    <Set name="Port">8443</Set>
    <Set name="maxIdleTime">30000</Set>
    <Set name="handshakeTimeout">2000</Set>
    <Set name="keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="password">xxxxxx</Set>
    <Set name="keyPassword">xxxxxx</Set>
    <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="trustPassword">OBF:xxxxx</Set>
    <Set name="handshakeTimeout">2000</Set>
    <!-- Set name="ThreadPool">
      <New class="org.mortbay.thread.BoundedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">250</Set>
     </New>
    </Set -->
  </New>
 </Arg>
</Call>



<!-- Default SSL Connector for https port 443 -->
<Call name="addConnector">
 <Arg>
  <New class="org.mortbay.jetty.security.SslSocketConnector">
    <Set name="Port">443</Set>
    <Set name="maxIdleTime">30000</Set>
    <Set name="handshakeTimeout">2000</Set>
    <Set name="keystore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="password">xxxxxx</Set>
    <Set name="keyPassword">xxxxxx</Set>
    <Set name="truststore"><SystemProperty name="jetty.home" default="." />/etc/keystore</Set>
    <Set name="trustPassword">OBF:xxxxx</Set>
    <Set name="handshakeTimeout">2000</Set>
    <!-- Set name="ThreadPool">
      <New class="org.mortbay.thread.BoundedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">250</Set>
     </New>
    </Set -->
  </New>
 </Arg>
</Call>

For the 2nd and 4th connectors, the only real differences are the port numbers. In short, you can configure multiple ports per connector/protocol, but you cannot configure multiple protocols/connectors for the same port.