透過Certbot為Apache網站申請憑證
前言
筆者在Ubuntu 20.04的docker container內用Apache2架了一個網站(已有domain name),本來只能透過http訪問,參考certbot instructions - Apache on Ubuntu 20.04為它申請憑證後,就能透過https訪問了。
安裝certbot
透過apt
certbot instructions - Apache on Ubuntu 20.04中要求我們先安裝snap
,然後再透過snap
安裝certbot
,但是根據Unable to install snapcraft snap in docker image(ubuntu:19.10)),似乎沒有簡單的方式能在docker內安裝snap
。
以下是筆者嘗試過行不通的路(Installing snap on Ubuntu):
sudo apt install snapd -y
sudo snap install hello-world
會出現以下錯誤:
error: cannot communicate with server: Post http://localhost/v2/snaps/hello-world: dial unix /run/snapd.socket: connect: no such file or directory
後來發現certbot instructions - Apache on Ubuntu 20.04只是建議讀者用snap
安裝certbot
,因此snap
並不是必要的,透過apt
安裝certbot
也可以:
apt-get install -y certbot
透過snap
根據Installing snapd,Ubuntu 20.04中自帶snap
,如果是在一般的機器上,可以使用以下指令安裝certbot
:
sudo snap install core
sudo snap refresh core
sudo apt remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
獲取並安裝certificates
透過以下指令獲取並安裝certificates
certbot --apache
過程中會需要輸入domain name。
測試憑證的自動更新
透過以下指令測試憑證的自動更新:
sudo certbot renew --dry-run
檢查憑證到期日
參考How to find Certifications Expiry Date,使用以下指令檢查:
sudo openssl x509 -dates -noout -in /etc/letsencrypt/live/<your_domain_name>/cert.pem
輸出如下:
notBefore=Jul 13 00:06:28 2021 GMT
notAfter=Oct 11 00:06:27 2021 GMT
擴展到其它domain name
上面只為example.com申請了憑證,如果使用Firefox拜訪https://www.example.com會出現如下提示:
這代表我們需要為www.example.com申請一個憑證。我們可以使用如下指令來將之前申請過的憑證拓展到www.example.com:
sudo certbot certonly --standalone -d example.com -d www.example.com
如果中途出現以下錯誤:
Problem binding to port 80: Could not bind to IPv4 or IPv6
則需先關掉Apache:
service apache2 stop
以下為成功執行的log:
redirect http to https and www to non-www
如果想將:
http://example.com
http://www.example.com
https://www.example.com
都重導向至:
https://example.com
查看/etc/apache2/sites-available/
目錄,下面應該會有一個<website>-le-ssl.conf
,它是基於<website>.conf
,由Let’s Encrypt自動生成的:
<IfModule mod_ssl.c>
<VirtualHost *:443>
DocumentRoot /your/document/root
PassengerRoot /usr/share/rvm/gems/ruby-2.7.0/gems/passenger-6.0.7
PassengerDefaultRuby /usr/share/rvm/gems/ruby-2.7.0/wrappers/ruby
PassengerUser redmine
<Directory /your/document/root>
AllowOverride all # added
Allow from all
Options -MultiViews
Require all granted
</Directory>
ServerName example.com
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:80>
DocumentRoot /your/document/root
PassengerRoot /usr/share/rvm/gems/ruby-2.7.0/gems/passenger-6.0.7
PassengerDefaultRuby /usr/share/rvm/gems/ruby-2.7.0/wrappers/ruby
PassengerUser redmine
<Directory /your/document/root>
AllowOverride all # added
Allow from all
Options -MultiViews
Require all granted
</Directory>
</VirtualHost>
</IfModule>
由certbot自動生成的<website>-le-ssl.conf
如下:
<IfModule mod_ssl.c>
<VirtualHost *:443>
DocumentRoot /your/document/root
PassengerRoot /usr/share/rvm/gems/ruby-2.6.6/gems/passenger-6.0.8
PassengerDefaultRuby /usr/share/rvm/gems/ruby-2.6.6/wrappers/ruby
PassengerUser redmine
<Directory /your/document/root>
Allow from all
Options -MultiViews
Require all granted
</Directory>
ServerName example.com
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
在<VirtualHost *:443>
及<VirtualHost *:80>
的<Directory /your/document/root>
區塊內都加上這一行,來啟用等一下會新建的.htaccess
文件:
AllowOverride all
然後到/your/document/root
,新增一個.htaccess
文件,內容如下:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
最後再重啟Apache即可:
service apache2 restart
透過Chrome測試
按F12,點選下面的Network Conditions
標籤頁,在Caching
這一欄把Disable cache
勾起來。
前往http://example.com
,http://www.example.com
,https://www.example.com
中的其中一個網址,按F5後應該要有一行的Status是301。
透過Firefox測試
按F12,點選工具箱選項
,在進階設定
裡把停用HTTP快取(開啟工具箱時)
勾起來。
undo
可參考A command to undo my CertBot command (to uninstall the cert stack)?
certbot相關指令
How to totally remove a certbot-created SSL certificate?
列出所有證書:
sudo certbot certificates
刪除之前所申請的證書:
sudo certbot delete --cert-name <domain_name>
在已有domain name和證書的情況下,再為另一個domain name申請證書
Certbot add www domain to existing domain certificate
sudo certbot certonly --cert-name <new_domain_name> -d <new_domain_name>
Saving debug log to /var/log/letsencrypt/letsencrypt.log
How would you like to authenticate with the ACME CA?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Apache Web Server plugin (apache)
2: Runs an HTTP server locally which serves the necessary validation files under
the /.well-known/acme-challenge/ request path. Suitable if there is no HTTP
server already running. HTTP challenge only (wildcards not supported).
(standalone)
3: Saves the necessary validation files to a .well-known/acme-challenge/
directory within the nominated webroot path. A seperate HTTP server must be
running and serving files from the webroot path. HTTP challenge only (wildcards
not supported). (webroot)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-3] then [enter] (press 'c' to cancel): 3
此處如果選擇webroot
選項,接下來會需要輸入有index.html
的目錄,這裡填入/var/www/html
:
Requesting a certificate for <new_domain_name>
Input the webroot for <new_domain_name>: (Enter 'c' to cancel): /var/www/html
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/<new_domain_name>/fullchain.pem
Key is saved at: /etc/letsencrypt/live/<new_domain_name>/privkey.pem This certificate expires on <new_expiration_date>.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
修改Apache2支援的SSL/TLS版本
編輯/etc/apache2/mods-available/ssl.conf
,將:
SSLProtocol all -SSLv3
改成:
SSLProtocol +TLSv1.2
可解決NVT: SSL/TLS: Deprecated TLSv1.0 and TLSv1.1 Protocol Detection
的問題。
參考disable Secure Renegotiation in apache httpd 2.4,如欲解決NVT: SSL/TLS: Renegotiation DoS Vulnerability (CVE-2011-1473, CVE-2011-5094)
的問題,編輯/etc/apache2/sites-available/redmine-le-ssl.conf
,加入:
SSLOptions +StrictRequire +StdEnvVars -OptRenegotiate
之後重啟apache2:
systemctl restart apache2
參考連結
certbot instructions - Apache on Ubuntu 20.04
Letsencrypt certificate for www and non-www domain