Guides: How to get a free certificate and use SSL with Ktor

预计阅读时间:8分钟

目录:

你可以购买一个证书,并配置Ktor使用它, 或者你可以用Let的加密自动获取一个免费的证书服务https://wss://与Ktor请求. 在此页面中,您将发现如何实现此目的,方法是将Ktor配置为直接为单个域提供SSL证书,或者将Docker与nginx一起使用,以轻松地为单台计算机上不同容器中的不同应用程序提供服务.

Option1: With Ktor serving SSL directly

Configuring an A register pointing to the machine

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

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

Generating a certificate

Ktor服务器必须未运行,并且您必须执行以下命令(更改my.example.comroot@example.com8889 ).

此命令将在指定的端口(必须在公用网络中以端口80可用,或者您可以将路由器中的端口转发到80:8889,并且域必须指向您的公用IP)上启动HTTP Web服务器.然后将请求质询,使用适当的内容公开/.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
Failed authorization procedure. my.example.com (http-01): urn:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://my.example.com/.well-known/acme-challenge/j-BJXA5ZGXdJuZhTByL4B95XBpiaGjZsm8JdCcA3Vr4: Timeout during connect (likely firewall problem)

IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: my.example.com
   Type:   connection
   Detail: Fetching
   http://my.example.com/.well-known/acme-challenge/j-BJXA5ZGXdJuZhTByL4B9zXBp3aGjZsm8JdCcA3Vr4:
   Timeout during connect (likely firewall problem)

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address. Additionally, please check that
   your computer has a publicly routable IP address and that no
   firewalls are preventing the server from communicating with the
   client. If you're using the webroot plugin, you should also verify
   that you are serving files from the webroot path you provided.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.

✅工作输出样本:

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

Converting the private key and certificate for Ktor

现在,您必须将certbot编写的私钥和证书转换为certbot可以理解的格式.

链和私钥分别作为fullchain.pemprivkey.pem存储在/etc/letsencrypt/live/$DOMAIN中.

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

Configuring Ktor to use the generated 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上侦听.

Option2: With Docker and Nginx as reverse proxy

当将Docker与多个域一起使用时,您可能想使用nginx-proxy映像和letsencrypt-nginx-proxy-companion映像在单个机器/ ip上为多个域/子域提供服务,并使用Let's Encrypt自动提供HTTPS.

在这种情况下,您将使用NGINX创建一个容器,并可能监听端口80443 ;仅在容器之间可访问的内部网络,以便nginx可以连接和反向代理您的网站(包括websocket);以及一个NGINX伙伴,通过内部检查来处理域证书配置的Docker容器.

Creating a internal docker network

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

docker network create --driver bridge reverse-proxy

Creating an Nginx container

现在我们必须创建一个运行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因此--restart=always守护进程在重启机器时重启容器.
  • --network=reverse-proxy因此NGINX在该网络中,并且可以连接到同一网络中的其他容器.
  • -v certs:ro该卷将与letsencrypt-companion共享以访问每个域的证书.
  • -v conf, vhost以便在必须进行一些调整的情况下-v conf, vhost此配置是持久的,可以从外部访问.
  • -v /var/run/docker.sock这可以使该映像获得有关在守护程序中运行的新容器的通知/自省.
  • -e --label-e --label使用的-e --label方法是将该映像标识为NGINX.

You can adjust /home/virtual/nginx* paths to the path you prefer.

Creating a Nginx Let’s Encrypt companion container

使用nginx-proxy容器,现在我们可以创建一个伴随容器,该容器将请求并续订证书:

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
  • --restart=always作为NGINX映像,以在引导时重新启动.
  • --network=reverse-proxy它必须与NGINX代理容器位于同一网络上才能与其通信.
  • --volumes-from nginx它可以访问与NGINX容器相同的卷,因此它可以在/usr/share/nginx/html内编写.well .well-known挑战.
  • -v certs:rw它需要写访问权限才能写入私钥和证书,以便NGINX提供.
  • -v /var/run/docker.sock要求访问docker事件和自省以确定要请求的证书.

Creating a service

现在,我们已经配置了NGINX和Let's Encrypt伴侣,因此它们将根据环境变量VIRTUAL_HOSTVIRTUAL_PORTLETSENCRYPT_HOSTLETSENCRYPT_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"]

您可以找到有关如何部署docker和Dockerfile的更多信息.

Simplified overview

#direction: right
#.internet: fill=#fee
#.network: fill=#efe
#.http: fill=#6f6
#.ssl: fill=#6af

[<internet>Internet]

[<http>Nginx
|port=80 (HTTP, WS)
|port=443 (HTTPS and WSS)
|TLS certs per domain
|VIRTUAL_HOST
|VIRTUAL_PORT
]

[App
|[port=8080 HTTP & WS]
|[<http>VIRTUAL_HOST=myhost.com]
|[<http>VIRTUAL_PORT=8080]
|[<ssl>LETSENCRYPT_HOST=myhost.com]
|[<ssl>LETSENCRYPT_EMAIL=email@myhost.com]
]

[<ssl>Let's Encrypt companion
|LETSENCRYPT_HOST
|LETSENCRYPT_EMAIL]

[Docker
|port=80,443
]

[Let's Encrypt] <- cert request [Let's Encrypt companion]

[App] -:> [reverse-proxy]

[<network>reverse-proxy|network]
[Nginx] <- [reverse-proxy]

[Internet] <- port 80, 443[Docker]
[Docker] <- [Nginx]

[Let's Encrypt companion] <-> [Nginx]

The XForwardedHeaderSupport feature

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

by  ICOPY.SITE