前言
之前寫過一篇透過Certbot為Apache網站申請憑證,本篇記錄更新憑證時所踩過的坑及解決方式。
Prerequisite
更新憑證前須先檢查是否能從外部訪問http://127.0.0.1:80/index.html
,如果不行,可以跟著下節踩坑記錄一步一步排查問題。
踩坑記錄
使用以下指令嘗試更新憑證:
sudo certbot renew --dry-run -v
但是卻出現如下錯誤:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.xxx.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Simulating renewal of an existing certificate for www.xxx.com
Performing the following challenges:
http-01 challenge for www.xxx.com
Waiting for verification...
Challenge failed for domain www.xxx.com
http-01 challenge for www.xxx.com
Certbot failed to authenticate some domains (authenticator: apache). The Certificate Authority reported these problems:
Domain: www.xxx.com
Type: connection
Detail: Fetching http://www.xxx.com/.well-known/acme-challenge/ndayPNUW2cqi0kHUkDN9rlLG1ir6om9T0Bq1_0TSYuj: Timeout during connect (likely firewall problem)
Hint: The Certificate Authority failed to verify the temporary Apache configuration changes made by Certbot. Ensure that the listed domains point to this Apache server and that it is accessible from the internet.
Cleaning up challenges
Failed to renew certificate www.xxx.com with error: Some challenges have failed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All simulated renewals failed. The following certificates could not be renewed:
/etc/letsencrypt/live/www.xxx.com/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
log中提到了http-01 challenge(HTTP-01 考驗),參考Challenge Types - Let’s Encrypt - Free SSL/TLS Certificates,HTTP-01 考驗是最常用的考驗,它只接受port 80和443。
得知HTTP-01 考驗跟port 80和443有關後,使用port checker檢查該網站,發現port 80和443都是關閉的。
從防火牆打開port 80和443後再重新嘗試,出現了不一樣的錯誤:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.xxx.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Simulating renewal of an existing certificate for www.xxx.com
Performing the following challenges:
http-01 challenge for www.xxx.com
Waiting for verification...
Challenge failed for domain www.xxx.com
http-01 challenge for www.xxx.com
Certbot failed to authenticate some domains (authenticator: apache). The Certificate Authority reported these problems:
Domain: www.xxx.com
Type: unauthorized
Detail: Invalid response from http://www.xxx.com/.well-known/acme-challenge/68aFGxZhRRBXrRRYHmyF7C-5Qcxoi_cS1xg53SaeM2M [210.66.16.233]: "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<style>.center{font-family:Verdana,Arial,sans-serif}.center:lang(zh-TW){fon"
Hint: The Certificate Authority failed to verify the temporary Apache configuration changes made by Certbot. Ensure that the listed domains point to this Apache server and that it is accessible from the internet.
Cleaning up challenges
Failed to renew certificate www.xxx.com with error: Some challenges have failed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All simulated renewals failed. The following certificates could not be renewed:
/etc/letsencrypt/live/www.xxx.com/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
當中的Invalid response from ...
表示Let’s Encrypt所獲取的網頁內容並不是它所期待的。
(因為.well-known/acme-challenge/68aFGxZhRRBXrRRYHmyF7C-5Qcxoi_cS1xg53SaeM2M
網頁與index.html
同樣都是位於/var/www
底下(?),所以下面檢查的是index.html
這個網頁。)
首先從機器內部檢查,試著用以下指令抓取http://127.0.0.1:80/index.html
網頁:
curl http://127.0.0.1:80/index.html
出現了以下錯誤:
Not Found: /index.html
index.html
在機器內部對應的是/var/www/html/index.html
這個網頁,而該網頁則是由view /etc/apache2/sites-available/000-default.conf
這個設定檔來管理,其內容如下:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
參考getting 404 not found - website with apache2 on ubuntu,使用以下指令啟用000-default.conf
這個網頁:
sudo a2ensite 000-default
並編輯/etc/apache2/apache2.conf
:
sudo vim /etc/apache2/apache2.conf
將這部份的設定:
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
改成:
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory /usr/share>
AllowOverride None
Require all granted
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
然後:
sudo systemctl restart apache2
sudo a2enmod rewrite
接著重新執行curl http://127.0.0.1:80/index.html
,就能獲取index.html
文件裡面的內容。
接著嘗試從外部訪問,發現一樣出現404的問題,到這裡已經可以確認是防火牆的問題了。檢查後發現:從外網(WAN)訪問port 80會被轉發到其它機器,而不是www.xxx.com
這台機器的port 80。改將外網的port 80轉發到www.xxx.com
這台機器的port 80後,就能成功更新憑證了。
For confirmation purpose, index.html
裡的內容如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
Modified from the Debian original for Ubuntu
Last updated: 2016-11-16
See: https://launchpad.net/bugs/1288690
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Apache2 Ubuntu Default Page: It works</title>
<style type="text/css" media="screen">
* {
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
}
body, html {
padding: 3px 3px 3px 3px;
background-color: #D8DBE2;
font-family: Verdana, sans-serif;
font-size: 11pt;
text-align: center;
}
div.main_page {
position: relative;
display: table;
width: 800px;
margin-bottom: 3px;
margin-left: auto;
margin-right: auto;
padding: 0px 0px 0px 0px;
border-width: 2px;
border-color: #212738;
border-style: solid;
background-color: #FFFFFF;
text-align: center;
}
div.page_header {
height: 99px;
width: 100%;
background-color: #F5F6F7;
}
div.page_header span {
margin: 15px 0px 0px 50px;
font-size: 180%;
font-weight: bold;
}
div.page_header img {
margin: 3px 0px 0px 40px;
border: 0px 0px 0px;
}
div.table_of_contents {
clear: left;
min-width: 200px;
margin: 3px 3px 3px 3px;
background-color: #FFFFFF;
text-align: left;
}
div.table_of_contents_item {
clear: left;
width: 100%;
margin: 4px 0px 0px 0px;
background-color: #FFFFFF;
color: #000000;
text-align: left;
}
div.table_of_contents_item a {
margin: 6px 0px 0px 6px;
}
div.content_section {
margin: 3px 3px 3px 3px;
background-color: #FFFFFF;
text-align: left;
}
div.content_section_text {
padding: 4px 8px 4px 8px;
color: #000000;
font-size: 100%;
}
div.content_section_text pre {
margin: 8px 0px 8px 0px;
padding: 8px 8px 8px 8px;
border-width: 1px;
border-style: dotted;
border-color: #000000;
background-color: #F5F6F7;
font-style: italic;
}
div.content_section_text p {
margin-bottom: 6px;
}
div.content_section_text ul, div.content_section_text li {
padding: 4px 8px 4px 16px;
}
div.section_header {
padding: 3px 6px 3px 6px;
background-color: #8E9CB2;
color: #FFFFFF;
font-weight: bold;
font-size: 112%;
text-align: center;
}
div.section_header_red {
background-color: #CD214F;
}
div.section_header_grey {
background-color: #9F9386;
}
.floating_element {
position: relative;
float: left;
}
div.table_of_contents_item a,
div.content_section_text a {
text-decoration: none;
font-weight: bold;
}
div.table_of_contents_item a:link,
div.table_of_contents_item a:visited,
div.table_of_contents_item a:active {
color: #000000;
}
div.table_of_contents_item a:hover {
background-color: #000000;
color: #FFFFFF;
}
div.content_section_text a:link,
div.content_section_text a:visited,
div.content_section_text a:active {
background-color: #DCDFE6;
color: #000000;
}
div.content_section_text a:hover {
background-color: #000000;
color: #DCDFE6;
}
div.validator {
}
</style>
</head>
<body>
<div class="main_page">
<div class="page_header floating_element">
<img src="/icons/ubuntu-logo.png" alt="Ubuntu Logo" class="floating_element"/>
<span class="floating_element">
Apache2 Ubuntu Default Page
</span>
</div>
<!-- <div class="table_of_contents floating_element">
<div class="section_header section_header_grey">
TABLE OF CONTENTS
</div>
<div class="table_of_contents_item floating_element">
<a href="#about">About</a>
</div>
<div class="table_of_contents_item floating_element">
<a href="#changes">Changes</a>
</div>
<div class="table_of_contents_item floating_element">
<a href="#scope">Scope</a>
</div>
<div class="table_of_contents_item floating_element">
<a href="#files">Config files</a>
</div>
</div>
-->
<div class="content_section floating_element">
<div class="section_header section_header_red">
<div id="about"></div>
It works!
</div>
<div class="content_section_text">
<p>
This is the default welcome page used to test the correct
operation of the Apache2 server after installation on Ubuntu systems.
It is based on the equivalent page on Debian, from which the Ubuntu Apache
packaging is derived.
If you can read this page, it means that the Apache HTTP server installed at
this site is working properly. You should <b>replace this file</b> (located at
<tt>/var/www/html/index.html</tt>) before continuing to operate your HTTP server.
</p>
<p>
If you are a normal user of this web site and don't know what this page is
about, this probably means that the site is currently unavailable due to
maintenance.
If the problem persists, please contact the site's administrator.
</p>
</div>
<div class="section_header">
<div id="changes"></div>
Configuration Overview
</div>
<div class="content_section_text">
<p>
Ubuntu's Apache2 default configuration is different from the
upstream default configuration, and split into several files optimized for
interaction with Ubuntu tools. The configuration system is
<b>fully documented in
/usr/share/doc/apache2/README.Debian.gz</b>. Refer to this for the full
documentation. Documentation for the web server itself can be
found by accessing the <a href="/manual">manual</a> if the <tt>apache2-doc</tt>
package was installed on this server.
</p>
<p>
The configuration layout for an Apache2 web server installation on Ubuntu systems is as follows:
</p>
<pre>
/etc/apache2/
|-- apache2.conf
| `-- ports.conf
|-- mods-enabled
| |-- *.load
| `-- *.conf
|-- conf-enabled
| `-- *.conf
|-- sites-enabled
| `-- *.conf
</pre>
<ul>
<li>
<tt>apache2.conf</tt> is the main configuration
file. It puts the pieces together by including all remaining configuration
files when starting up the web server.
</li>
<li>
<tt>ports.conf</tt> is always included from the
main configuration file. It is used to determine the listening ports for
incoming connections, and this file can be customized anytime.
</li>
<li>
Configuration files in the <tt>mods-enabled/</tt>,
<tt>conf-enabled/</tt> and <tt>sites-enabled/</tt> directories contain
particular configuration snippets which manage modules, global configuration
fragments, or virtual host configurations, respectively.
</li>
<li>
They are activated by symlinking available
configuration files from their respective
*-available/ counterparts. These should be managed
by using our helpers
<tt>
a2enmod,
a2dismod,
</tt>
<tt>
a2ensite,
a2dissite,
</tt>
and
<tt>
a2enconf,
a2disconf
</tt>. See their respective man pages for detailed information.
</li>
<li>
The binary is called apache2. Due to the use of
environment variables, in the default configuration, apache2 needs to be
started/stopped with <tt>/etc/init.d/apache2</tt> or <tt>apache2ctl</tt>.
<b>Calling <tt>/usr/bin/apache2</tt> directly will not work</b> with the
default configuration.
</li>
</ul>
</div>
<div class="section_header">
<div id="docroot"></div>
Document Roots
</div>
<div class="content_section_text">
<p>
By default, Ubuntu does not allow access through the web browser to
<em>any</em> file apart of those located in <tt>/var/www</tt>,
<a href="http://httpd.apache.org/docs/2.4/mod/mod_userdir.html" rel="nofollow">public_html</a>
directories (when enabled) and <tt>/usr/share</tt> (for web
applications). If your site is using a web document root
located elsewhere (such as in <tt>/srv</tt>) you may need to whitelist your
document root directory in <tt>/etc/apache2/apache2.conf</tt>.
</p>
<p>
The default Ubuntu document root is <tt>/var/www/html</tt>. You
can make your own virtual hosts under /var/www. This is different
to previous releases which provides better security out of the box.
</p>
</div>
<div class="section_header">
<div id="bugs"></div>
Reporting Problems
</div>
<div class="content_section_text">
<p>
Please use the <tt>ubuntu-bug</tt> tool to report bugs in the
Apache2 package with Ubuntu. However, check <a
href="https://bugs.launchpad.net/ubuntu/+source/apache2"
rel="nofollow">existing bug reports</a> before reporting a new bug.
</p>
<p>
Please report bugs specific to modules (such as PHP and others)
to respective packages, not to the web server itself.
</p>
</div>
</div>
</div>
<div class="validator">
</div>
</body>
</html>
模擬更新成功的訊息如下:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.xxx.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Simulating renewal of an existing certificate for www.xxx.com
Performing the following challenges:
http-01 challenge for www.xxx.com
Waiting for verification...
Cleaning up challenges
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/www.xxx.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
看到上述訊息後,就可以實際來更新了:
sudo certbot renew -v
出現以下訊息,表示成功更新:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/www.xxx.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Certificate is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Renewing an existing certificate for www.xxx.com
Performing the following challenges:
http-01 challenge for www.xxx.com
Waiting for verification...
Cleaning up challenges
Reloading apache server after certificate renewal
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded:
/etc/letsencrypt/live/www.xxx.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
檢查
參考How to find Certifications Expiry Date,使用以下指令檢查憑證到期日:
sudo openssl x509 -dates -noout -in /etc/letsencrypt/live/www.xxx.com/fullchain.pem
notBefore=Apr 19 06:36:08 2024 GMT
notAfter=Jul 18 06:36:07 2024 GMT
這時如果從網頁上看,憑證的到期日可能還是舊的,記得要重啟apache2服務網頁上的到期日才會更新:
systemctl restart apache2
其它
參考Certbot 申請 SSL certificate 錯誤問題,如果webroot並不是在預期中的位置,可以在憑證更新指令後面加--webroot-path /var/www/html/
或-w /var/www/html/
來解決。
參考HTTP Validation (http-01),HTTP-01考驗需要在webroot資料夾下創建文件,如果出現權限不足的問題,可以自己手動在/var/www/html
下創建.well-known/acme-challenge
,並將它的所有者改為自己。