JKS文件格式

  JKS(Java KeyStore)是Java和Ktor使用的证书格式。

  你可以使用keytool来转换和管理这些证书。

CER文件格式

keytool -import -v -trustcacerts -alias keyAlias -file server.cer -keystore cacerts.jks -keypass changeit
复制代码

SSL

  您可以购买证书并配置Ktor使用它,或者您可以使用Let's Encrypt自动获取免费证书以使用Ktor提供https://和wss://请求。

  将Ktor配置为直接为单个域提供SSL证书,或者使用Docker和nginx轻松地在单个计算机上的不同容器中提供不同的应用程序。

使用Ktor直接提供的SSL

  首先,您必须将域或子域配置为指向要用于证书的计算机的IP。 你必须在这里放置机器的公共IP。 如果该计算机位于路由器后面,则需要将路由器配置为使用主机对机器进行DMZ,或者至少将端口80(HTTP)重定向到该计算机,稍后您可能需要配置端口443(HTTPS )也是。

注:即使您将Ktor配置为绑定到另一个端口,Let’s Encrypt也将始终访问公共IP的PORT 80,您必须配置路由以将端口80重定向到托管ktor的计算机的正确本地IP和端口。

  • 生成证书
      要Ktor服务器能运行,您必须执行以下命令(changing my.example.com, root@example.com and 8889)。 此命令将启动指定端口中的HTTP Web服务器(必须在公共网络中作为端口80使用,或者您可以将路由器中的端口转发到80:8889,并且域必须指向您的公共IP),它 然后将请求,使用适当的内容公开/.well-known/acme-challenge/file,生成域私钥,并检索证书链:
export DOMAIN=my.example.com
export EMAIL=root@example.com
export PORT=8889
export ALIAS=myalias
certbot certonly -n -d $DOMAIN --email "$EMAIL" --agree-tos --standalone --preferred-challenges http --http-01-port $PORT
复制代码

  配置正常后会生成如下信息:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for my.example.com
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/my.example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/my.example.com/privkey.pem
Your cert will expire on 2018-09-27. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
Donating to EFF:                    https://eff.org/donate-le
复制代码
  • 转换Ktor的私钥和证书
    现在,您必须将certbot编写的私钥和证书转换为Ktor可以理解的格式。 链和私钥存储在/etc/letsencrypt/live/$DOMAIN中,作为fullchain.pem和privkey.pem。
openssl pkcs12 -export -out /etc/letsencrypt/live/$DOMAIN/keystore.p12 -inkey /etc/letsencrypt/live/$DOMAIN/privkey.pem -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem -name $ALIAS
复制代码

这将为导出请求密码(您需要提供一个用于下一步工作的密码):

Enter Export Password: mypassword
Verifying - Enter Export Password: mypassword
复制代码

使用p12文件,我们可以使用keytool cli生成JKS文件:

keytool -importkeystore -alias $ALIAS -destkeystore /etc/letsencrypt/live/$DOMAIN/keystore.jks -srcstoretype PKCS12 -srckeystore /etc/letsencrypt/live/$DOMAIN/keystore.p12
复制代码
  • 配置Ktor以使用生成的JKS
    现在,您必须更新application.conf HOCON文件,以配置SSL端口,keyStore,别名和密码。 您必须为特定情况设置正确的值:
ktor {
  deployment {
      port = 8889
      port = ${?PORT}
      sslPort = 8890
      sslPort = ${?PORT_SSL}
  }
  application {
      modules = [ com.example.ApplicationKt.module ]
  }
  security {
      ssl {
          keyStore = /etc/letsencrypt/live/mydomain.com/keystore.jks
          keyAlias = myalias
          keyStorePassword = mypassword
          privateKeyPassword = mypassword
      }
  }
}
复制代码

如果一切顺利,Ktor应该在HTTP中侦听端口8889并在HTTPS中侦听端口8890。

使用Docker和Nginx作为反向代理

  使用具有多个域的Docker时,您可能希望使用nginx-proxy映像和letsencrypt-nginx-proxy-companion映像在单个计算机/ip上提供多个域/子域,并使用Let's Encrypt自动提供HTTPS。

  在这种情况下,您使用NGINX创建一个容器,可能会侦听端口80和443,内部网络只能在容器之间访问,因此nginx可以连接和反向代理您的网站(包括websockets),以及NGINX通过处理域证书 配置Docker容器。

  • 创建内部docker网络

  第一步是创建一个我们将使用的桥接网络,以便nginx可以连接到其他容器以反向代理用户的HTTP,HTTPS,WS和WSS请求:

docker network create --driver bridge reverse-proxy
复制代码
  • 创建一个Nginx容器
    现在我们必须创建一个运行NGINX的容器来执行反向代理:
docker rm -f nginx
 docker run -d -p 80:80 -p 443:443 \
  --name=nginx \
  --restart=always \
  --network=reverse-proxy \
  -v /home/virtual/nginx/certs:/etc/nginx/certs:ro \
  -v /home/virtual/nginx/conf.d:/etc/nginx/conf.d \
  -v /home/virtual/nginx/vhost.d:/etc/nginx/vhost.d \
  -v /home/virtual/nginx/html:/usr/share/nginx/html \
  -v /var/run/docker.sock:/tmp/docker.sock:ro \
  -e NGINX_PROXY_CONTAINER=nginx \
  --label com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true \
  jwilder/nginx-proxy
复制代码

--restart=always 当重新启动机器时,docker守护程序会重新启动容器。 --network=reverse-proxy NGINX在该网络中,可以连接到同一网络中的其他容器。 -v certs:ro 此卷将与letsencrypt-companion共享,以访问每个域的证书。 -v conf, vhost 如果您需要进行一些调整,这种配置是持久的,可以从外部访问。 -v /var/run/docker.sock 这允许此image获得有关在守护程序中运行的新容器的通知。 -e --label 由同伴使用,将此image标识为NGINX。

注:您可以将/home/virtual/nginx *路径调整为您喜欢的路径。

  • 使用Let’s Encrypt来创建Nginx容器
docker rm -f nginx-letsencrypt
 docker run -d \
 --name nginx-letsencrypt \
 --restart=always \
 --network=reverse-proxy \
 --volumes-from nginx \
 -v /home/virtual/nginx/certs:/etc/nginx/certs:rw \
 -v /var/run/docker.sock:/var/run/docker.sock:ro \
 jrcs/letsencrypt-nginx-proxy-companion
复制代码
  • 创建服务

  现在我们用Let’s Encrypt配置了NGINX,这样他们就会根据环境变量VIRTUAL_HOST,VIRTUAL_PORT和LETSENCRYPT_HOST,LETSENCRYPT_EMAIL自动反向代理您的网站,并为他们请求和提供证书。

  使用docker-compose,您可以创建一个docker-compose.yml文件(无需其他服务),如下所示:


docker-compose.yml

version: '2'
services:
  web:
    build:
      context: ./
      dockerfile: Dockerfile
    expose:
      - 8080
    environment:
      - VIRTUAL_HOST=mydomain.com
      - VIRTUAL_PORT=8080
      - LETSENCRYPT_HOST=mydomain.com
      - LETSENCRYPT_EMAIL=myemail@mydomain.com
    networks:
      - reverse-proxy
    restart: always

networks:
  backend:
  reverse-proxy:
    external:
      name: reverse-proxyv
复制代码

Dockerfile

FROM openjdk:8-jre-alpine

ENV APPLICATION_USER ktor
RUN adduser -D -g '' $APPLICATION_USER

RUN mkdir /app
RUN chown -R $APPLICATION_USER /app

USER $APPLICATION_USER

COPY ./build/libs/my-application.jar /app/my-application.jar
WORKDIR /app

CMD ["java", "-server", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCGroupMemoryLimitForHeap", "-XX:InitialRAMFraction=2", "-XX:MinRAMFraction=2", "-XX:MaxRAMFraction=2", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "my-application.jar"]
复制代码
XForwardedHeaderSupport功能

  在这种情况下,您使用nginx作为请求的反向代理。 如果要获取有关原始请求的信息,而不是代理的nginx请求,则必须使用XForwardedHeaderSupport功能。