幫 Apache Tomcat 7/9 上 HTTPS

近日敝單位踩到 HSTS 的地雷,於是就著手解決問題…

先說地雷的引爆點: 新上線 example.com 這網站給了 “strict-transport-security: max-age=31536000; includeSubDomains” 這組 HTTP header,使得原本透過 Apache Tomcat 提供服務的 http://system.example.com.tw:8080/ 網頁瀏覽異常;因瀏覽器參照 HSTS 後,只把 “http://” 改為 “https://” ,瀏覽器不知道應該同步修改連接埠號(port 8080)。

因為這幾台伺服器的網頁服務僅使用 Apache Tomcat,沒有 Apache HTTPDnginx 等其他軟體佔用 port 80 與 443,用 iptables 作 port redirection 就可以擺平,調整的方式會比較簡單。

需要作的事的大概就這些:

  • 取得 SSL certificates,並確認 renew 的時候可重新啟動 Apache Tomcat
  • 安裝 Tomcat Native
  • 調整 Tomcat 的 server.xml
  • 調整 iptables rules

Apache Tomcat 7 的 server.xml 用這段(某些參數視狀況調整):

<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
           maxThreads="200" SSLEnabled="true"
           SSLCertificateFile="/etc/letsencrypt/live/example.com/cert.pem"
           SSLCertificateKeyFile="/etc/letsencrypt/live/example.com/privkey.pem"
           SSLCACertificateFile="/etc/letsencrypt/live/example.com/chain.pem" />

Apache Tomcat 9 的 server.xml 用這段(某些參數視狀況調整),支援 HTTP/2:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
           maxThreads="200" SSLEnabled="true" >
  <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
  <SSLHostConfig>
    <Certificate certificateKeyFile="/etc/letsencrypt/live/example.com/privkey.pem"
                 certificateFile="/etc/letsencrypt/live/example.com/cert.pem"
                 certificateChainFile="/etc/letsencrypt/live/example.com/chain.pem"
                 type="RSA" />
  </SSLHostConfig>
</Connector>

iptables rules 增加以下這兩條:

/sbin/iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
/sbin/iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443