NGINX SSL

      在〈NGINX SSL〉中尚無留言

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 時,就不會出現找不到網頁的情形。

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *