Nginx 預設 80 port,網址開頭為 http:// ,這些資料使用明碼在網路上到處流竄,很容易被駭客攔截盜用,且現今的 Chrome 或是 Edge 都會在前面加上不安全的字樣,這會讓一般使用者誤以為是個危險的網站。
為了讓瀏覽器不再出現不安全的字樣,並防止駭客攔截資料,就必需使用 SSL 將資料加密,經過加密後的網址開頭會改成 https:// 。
SSL 全名為 Secure Sockets Layer,由 Netscape 在1994 年推出。伺服器與客戶端之間的通訊,皆經過加密才傳遞,所以就算訊息被攔截,攔截者也只會看到一堆亂碼而以,完全無法解碼。
本篇只適用在 Linux 下簽署 SSL,若要在 Windows 下簽署,請參考 Let’s Encrypt 官網說明。
先搞定 80 port
想要讓網站從 http:// 改成 https://,還是需先把 80 port 搞定。以本站為例,共設了四個網域,一個是 8900 port,另外三個是 80 port
server{ listen 8900; listen [::]:8900; server_name ~.*; root /server/thomas; index index.php index.html; add_header X-Frame-Options SAMEORIGIN; location ~* \.(ico|css|js|gif|jpe?g|png|ogg|ogv|svg|svgz|eot|otf|woff)(\?.+)?$ { expires max; log_not_found off; } location / { try_files $uri $uri/ /index.php?$args; } location ~* \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_split_path_info ^(.+\.php)(.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } server{ listen 80; listen [::]:80; server_name mahaljsp.asuscomm.com; root /server/wordpress; index index.php index.html; add_header X-Frame-Options SAMEORIGIN; location ~* \.(ico|css|js|gif|jpe?g|png|ogg|ogv|svg|svgz|eot|otf|woff)(\?.+)?$ { expires max; log_not_found off; } location / { try_files $uri $uri/ /index.php?$args; } location ~* \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_split_path_info ^(.+\.php)(.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } server{ listen 80; listen [::]:80; server_name mahaljsp.ddns.net; root /server/wordpress; index index.php index.html; add_header X-Frame-Options SAMEORIGIN; location ~* \.(ico|css|js|gif|jpe?g|png|ogg|ogv|svg|svgz|eot|otf|woff)(\?.+)?$ { expires max; log_not_found off; } location / { try_files $uri $uri/ /index.php?$args; } location ~* \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_split_path_info ^(.+\.php)(.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location /thomas { proxy_pass http://localhost:7002; proxy_set_header Host $http_host;#將客戶端的 HOST 傳入 Django proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /files { alias /data/server/wp_download; } } server { listen 80; listen [::]:80; server_name mahalpyweb.ddns.net; location / { proxy_pass http://localhost:7001; proxy_set_header Host $http_host;#將客戶端的 HOST 傳入 Django proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;#將客戶 ip 傳入Django } }
設定好要重啟 nginx,如果重啟失敗就要修改上面的設定,直到重啟成功才能繼續往下操作。
sudo nginx restart nginx
安裝 Let’s Encrypt certbot
接下來要取得第三方的 SSL 加密認証,大部份的第三方認証都需要付費,實在會讓人傾家盪產,還好有 Let’s Encrypt 可以免費使用,不過每三個月就要更新一次認証。請使用如下指令安裝 certbot 程式
sudo snap install --classic certbot sudo ln -s /snap/bin/certbot /usr/bin/certbot
第一次執行 certbot
使用如下指令執行 certbot
sudo certbot --nginx
第一次執行時,會要求輸入 eMail 及同意相關規定,並選擇要設定憑証的網站,如下
Saving debug log to /var/log/letsencrypt/letsencrypt.log Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel): mahaljsp@gmail.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please read the Terms of Service at https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must agree in order to register with the ACME server. Do you agree? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would you be willing, once your first certificate is successfully issued, to share your email address with the Electronic Frontier Foundation, a founding partner of the Let's Encrypt project and the non-profit organization that develops Certbot? We'd like to send you email about our work encrypting the web, EFF news, campaigns, and ways to support digital freedom. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y Account registered. Which names would you like to activate HTTPS for? We recommend selecting either all domains, or all domains in a VirtualHost/server block. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: mahaljsp.ddns.net 2: mahaljsp.asuscomm.com 3: mahalpyweb.ddns.net - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate numbers separated by commas and/or spaces, or leave input blank to select all options shown (Enter 'c' to cancel): 1 2 3 Requesting a certificate for mahaljsp.ddns.net
執行完 certbot 將憑証放在 /etc/letsencrypt/live/xxx.ddns.net 目錄下。憑証有二個,分別為 fullchain.pem及privkey.pem。
執行上面指令會自動更改 Nginx 設定檔,而且會自動重啟 nginx。
更改後的 nginx
certbot 執行後會自動增加 nginx 設定檔如下藍色的地方。
server{ listen 8900; listen [::]:8900; server_name ~.*; root /server/thomas; index index.php index.html; #不是 80 port 的設定,完全不變 } server{ server_name mahaljsp.asuscomm.com; root /server/wordpress; index index.php index.html; add_header X-Frame-Options SAMEORIGIN; location ~* \.(ico|css|js|gif|jpe?g|png|ogg|ogv|svg|svgz|eot|otf|woff)(\?.+)?$ { expires max; log_not_found off; } ....... listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/mahaljsp.asuscomm.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mahaljsp.asuscomm.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server{ server_name mahaljsp.ddns.net; root /server/wordpress; index index.php index.html; add_header X-Frame-Options SAMEORIGIN; location ~* \.(ico|css|js|gif|jpe?g|png|ogg|ogv|svg|svgz|eot|otf|woff)(\?.+)?$ { expires max; log_not_found off; } ...... listen [::]:443 ssl; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/mahaljsp.asuscomm.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mahaljsp.asuscomm.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { server_name mahalpyweb.ddns.net; location / { proxy_pass http://localhost:7001; proxy_set_header Host $http_host;#將客戶端的 HOST 傳入 Django proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;#將客戶 ip 傳入Django } listen [::]:443 ssl; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/mahaljsp.asuscomm.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/mahaljsp.asuscomm.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server{ if ($host = mahaljsp.asuscomm.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name mahaljsp.asuscomm.com; return 404; # managed by Certbot } server{ if ($host = mahaljsp.ddns.net) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name mahaljsp.ddns.net; return 404; # managed by Certbot } server { if ($host = mahalpyweb.ddns.net) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name mahalpyweb.ddns.net; return 404; # managed by Certbot }
certbot 只會更改原本是 80 port 的設定,如果原本的設定不是 80 port,就不會變更。
自動更新憑証
Let’s Encrypt 憑証有效日期只有三個月,所以使用 Linux 排程器 cron.d 每個月的 1 日 0:0 更新一次憑証,這樣就可以不用理會憑証是否到期。
請在 /etc/cron.d 新增 renewssl 檔案,內容如下。
0 0 1 * * root certbot renew --dry-run >> /home/thomas/renew_ssl.log
最後重啟 cron
sudo service cron reload 或是 sudo /etc/init.d/cron restart 或是 sudo systemctl restart cron
IP 分享器
ip 分享器 port forwarding 需將 443 port 指向伺服器的虛擬 ip。
Django CSRF
更改成 https 後,Django 的 CSRF 會一直無法驗証,需於 Django 的 settings.py 增加一行如下
CSRF_TRUSTED_ORIGINS = [https://xxx.ddns.net]
自行簽署 SSL 憑証 – 記錄用
不想使用第三方的 SSL 憑証,是可以自已簽署 SSL,不過客戶端還是會出現私人網站不安全的訊息,所以本段只是記錄而以,請不要跟著操作。
自行簽署的憑証的方法如下
sudo mkdir /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
然後依序如下填入相關訊息
Country Name (2 letter code) [AU]:TW State or Province Name (full name) [Some-State]:Taiwan Locality Name (eg, city) []:Changhua Organization Name (eg, company) [Internet Widgits Pty Ltd]:MyCompany Organizational Unit Name (eg, section) []:MyUnit Common Name (e.g. server FQDN or YOUR name) []: mahaljsp.asuscomm.com Email Address []:mahaljsp@gmail.com
將 /etc/nginx/sites-available/default 改成如下
server {
listen 80;
listen [::]:80;
rewrite ^(.*) https://mahaljsp.asuscomm.com permanent;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name mahaljsp.asuscomm.com;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
...
}
最後記得重啟 nginx
sudo systemctl restart nginx
上述 nginx 設定,會自動將 http 80 port 轉交 443 port,這樣客戶端輸入 http://mahaljsp.asuscomm.com 時,就不會出現找不到網頁的情形。