記一次Spring Boot專案部署,同時支援HTTP與HTTPS、80與443許可權問題

ImWiki發表於2019-03-01

最近把客戶端的內測分發平臺使用Spring Boot+Kotlin重構了,以前是用Tomcat部署的,現在改用Jar包部署。由於是比較簡單的單體應用,所以沒有使用持續整合框架Jenkins,都是通過FTP上傳到Tomcat目錄,然後重啟Tomcat。

同時支援HTTP與HTTPS

獲取SSL的簽名這裡就不說了,Google搜尋也有很多生成免費的簽名方案,我是把簽名檔案放在resources目錄

├── build.gradle
├── gradlew
├── settings.gradle
├── src
│   ├── main
│   │   ├── java
│   │   ├── kotlin
│   │   ├── resources
│   │   │   ├── application.properties
│   │   │   ├── keystore.p12
複製程式碼
方案一(不推薦,不無法相容HTTPS和HTTP)

直接修改application.properties

# 埠
server.port=8443
# 簽名路徑
server.ssl.key-store=/Users/Wiki/BetaServer/src/main/resources/keystore.p12
server.ssl.key-store-password=123123
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias:tomcat
複製程式碼

Spring本身就提供非常方便支援HTTPS的方式,直接修改application.properties即可實現HTTPS,但是使用這種方式就不能直接使用HTTP了。

方案二(相容HTTPS和HTTP)

我們在application.properties自定義了幾個引數

#HTTP埠
server.port=8080
#配置模SSL
tomcat.ssl.enable=true
tomcat.ssl.key-store=keystore.p12
tomcat.ssl.key-store-password=123123
tomcat.ssl.keyStoreType=PKCS12
tomcat.ssl.port=8443
複製程式碼

由於我是打包成Jar格式檔案然後放在伺服器執行,意味著resources目錄下的檔案無法獲取到絕對路徑或者相對路徑,我們換一個做法,我們在啟動HTTPS的時候把resources的檔案讀取出來,寫入到一個臨時的路徑,那麼就可以解決這個問題。

@ConditionalOnExpression(value = "${tomcat.ssl.enable:false}")
@Configuration
open class CustomTomcatSSLConfiguration {

    @Value("${tomcat.ssl.port:8443}")
    private val tomcatSSLPort: Int = 0

    @Value("${tomcat.ssl.key-store:}")
    private val tomcatSSLKeyStore: String? = null

    @Value("${tomcat.ssl.key-store-password:}")
    private val keystorePassword: String? = null

    @Value("${tomcat.ssl.keyStoreType:PKCS12}")
    private val keystoreType: String? = null

    @Bean
    open fun servletContainer(): ServletWebServerFactory {
        val tomcat = TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createSSLConnector())
        return tomcat;
    }
    open fun createSSLConnector(): Connector {
        // 由於下面需要填寫簽名的地址,如果我們打包成Jar,這個地址就失效了,從 resources 讀取 簽名檔案
        val stream = javaClass.classLoader.getResourceAsStream(tomcatSSLKeyStore)
        // 然後寫入當前應用執行的路徑
        val file = File(tomcatSSLKeyStore)
        file.writeBytes(stream.readBytes())

        val connector = Connector("org.apache.coyote.http11.Http11NioProtocol")
        connector.port = tomcatSSLPort;
        connector.secure = true
        connector.scheme = "https"

        connector.setAttribute("SSLEnabled", true)
        connector.setAttribute("sslProtocol", "TLS")
        connector.setAttribute("protocol", "org.apache.coyote.http11.Http11Protocol")
        connector.setAttribute("clientAuth", false)
        // 使用臨時的前面檔案路徑
        connector.setAttribute("keystoreFile", file.absolutePath)
        connector.setAttribute("keystoreType", keystoreType)
        connector.setAttribute("keystorePass", keystorePassword)
        connector.setAttribute("keyPass", keystorePassword)
        return connector
    }
}
複製程式碼
打包Jar

我的使用Gradle來代替Maven,打包非常的方便,直接執行命令打包即可

./gradlew bootJar
複製程式碼
上傳Jar到Linux伺服器

由於不是經常更新,所以沒有引入Jenkins,後續會考慮引入。以前我都是通過FTP上傳war到伺服器,然後重啟Tomcat來實現部署。最近我發現一個更加方便的做法,使用scp命令,可以實現把當前電腦的檔案上傳到伺服器。

scp -P 22222 build/libs/BetaServer.jar  apps@100.100.100.100:/home/apps/webapp/
複製程式碼
啟動Jar

我們都知道Jar的啟動是可以通過 java -jar BetaServer.jar即可啟動,但是當我們關閉命令視窗,這個程式就會被關閉導致服務也被關閉了,所以我們需要讓這個服務後臺執行,關閉視窗也不受影響。

nohup java -jar BetaServer.jar  > log.txt &
複製程式碼

記得不要把後面&忽略了,整行都是需要的,log.txt是原來命令列輸出的日誌,我們把它寫到檔案中,也方便我們後續檢視錯誤。

訪問伺服器

由於上面我們配置的HTTP是8080埠,HTTPS是8443埠,那麼我們就可以通過以下命令訪問

http://100.100.100.100:8080/index
https://100.100.100.100:8443/index
複製程式碼
修改埠對映

上面的訪問是帶有埠,但是我們釋出出去的網頁,肯定不能讓使用者也需要輸入埠,體驗太差了,我們要把HTTP的埠改成80、HTTPS改成443,那麼理論上就可以實現這樣訪問

http://100.100.100.100/index
https://100.100.100.100/index
複製程式碼

在Linux的下面部署了應用,為了安全我們使用非root使用者進行啟動,非root使用者不能監聽1024以下的埠號,如果直接改成80和443,會報安全性異常。

java.net.SocketException: Permission denied
複製程式碼

所以這裡需要使用linux的埠轉發機制,把到80埠的服務請求都轉到8080埠上,443埠轉發到8443。
在root下面執行一下命令:

$ iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
$ iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
$ service iptables save
複製程式碼

到這裡就大功告成啦。

相關文章