使用 VisualBox、nginx 搭建雙向驗證的網站

簡介

記錄我在 mac 上用 VisualBox 建立虛擬服務機后通過 nginx 搭建雙向驗證的網站的過程,包括虛擬機的建立、文件共享設置、虛擬機網絡設置、SSH 連接虛擬機、nginx 配置。

Linux Server (ubuntu) 的建立

用 VisualBox 建立一個 Linux Server 虛擬機(ubuntu-16.04.2-server-amd64),建立過程除了存儲那邊改選了固定大小其它的都是默認的選項。

虛擬機建立向導首頁
虛擬機建立向導存儲選擇

之后就是安裝系統。在虛擬機的設置里選擇存儲那一項的控制器 IDE 里的光驅選擇要裝的系統的鏡像文件文件,確認后啟動虛擬機裝好系統。

虛擬機系統鏡像文件選擇前
虛擬機系統鏡像文件選擇后

文件共享

為了實現虛擬機與 mac 文件共享要安裝增強功能,主機上根據 ubuntu 的版本下載 VBoxGuestAdditions 鏡像文件,然后和裝系統時一樣地在設置里的存儲里增加這個鏡像文件,在虛擬機界面的 Devices -> Optical Drives 里確保 VBoxGuestAdditions.iso 是打勾被選中的,然后在虛擬機里運行:

sudo mount /dev/cdrom /media/cdrom

進入 /media/cdrom 里面可以看到一些可執行文件,執行:

sudo ./VBoxGuestAdditions.run

重啟虛擬機:

sudo reboot

在虛擬機的設置里創建一個固定分配共享文件夾:

創建共享文件夾

共享文件夾自動掛載在虛擬機的 /media 目錄下,名稱是 sf_ 加上共享文件夾的名稱。這時訪問共享文件目錄非 root 用戶會出現權限問題(一般登錄的都是非 root 用戶):

訪問共享文件夾權限問題

運行以下命令:

sudo usermod -aG vboxsf 當前登錄的用戶名 # 如:sudo usermod -aG vboxsf cxswow

重啟虛擬機生效:

sudo reboot

共享文件完成。

網絡設置:NAT+Host-Only

虛擬機設置里默認的網絡是只有一張使用 NAT 的網卡,這時虛擬機可以上網,但是主機和虛擬機不互通,因此我要加一張網卡來讓主機可以訪問虛擬機,用的 Host-Only 模式。
在虛擬機關機的情況下打開虛擬機的設置 -> 網絡,網卡1默認的不用修改,打開網卡2,啟用網卡2的網絡連接,連接方式選 Host-Only,

虛擬機網卡2

這里要有一個界面名稱,如果沒有可選的,在 VirtualBox 的設置 -> 網絡里的 Host-Only 界面增加一個,用默認的設置就行。

增加一個 Host-Only

打開虛擬機,編輯網絡設置文件:

sudo vim /etc/network/interfaces

我的文件初始內容是這樣的:

網絡設置文件初始內容

這里的 auto 后面跟的是網卡名字,之后就是對這個網卡的一些設置。如果不知道對應的網卡的名字,運行以下命令可以查看當前網卡的信息:

ip link

這里可以看到新增加的網卡名字(我的是 enp0s8),所以我的網絡配置文件修改成以下這樣:

網絡設置修改后

重啟虛擬機網絡:

sudo /etc/init.d/networking restart
初始網絡信息
重啟后網絡信息

主機通過 ssh 連接虛擬機

通過密碼連接

確保虛擬機和客戶端都裝了 OpenSSL 的相關軟件后——如果在主機上用 ssh 連接虛擬機被拒絕了(Connection refused)一般就是虛擬機沒有安裝 ssh,虛擬機安裝 ssh 命令: sudo apt-get install openssh-client openssh-server——主機直接通過終端的 ssh 命令就能連上服務端:

ssh 虛擬機用戶名@虛擬機 IP 地址 # 如:ssh cxswow@192.168.56.101,這個 IP 是 Host-Only 的那個 IP

第一次連接一個虛擬機的時候會警告你要連接的這個機之前未知,讓你確認是否繼續連接,輸入 yes 繼續連接。然后會讓你輸入該機該用戶的密碼,輸入正確后就連接成功,此時就可以像在虛擬機的終端里一樣地使用了。

退出連接輸入:

exit

使用別名連接

每一次連接都輸入用戶名和 IP 是一件比較繁瑣的事,可以通過配置文件來給固定的用戶名和 IP 對起別名,之后通過別名連接會方便點。

做法是在客戶端的用戶根目錄下的 .ssh 文件夾里建立 config 文件,文件內容如下:

 Host myUbuntu
 User cxswow
 HostName 192.168.56.101

之后就可以通過下面的命令來連接了:

ssh myUbuntu

使用證書連接

每次都輸入密碼也不是一個好的選擇,通過密鑰認證連接會方便安全點。

在客戶端的用戶根目錄下的 .ssh 目錄下運行以下命令生成密鑰對:

ssh-keygen -b 1024 -t rsa

這里可選項 -b 后面跟的是密鑰的長度 1024 字節,最長 4096 字節,長度影響解密時間,一般 1024 或 2048 就足夠了;可選項 -t 后面跟的是加密方式,默認是 rsa,還要一種 dsa。
生成時會提示輸入密鑰名字,默認名字是 id_rsa ,我給命名成 mymac 了,這里如果使用自己命名的密鑰名字,之后將公鑰傳到虛擬機上的命令就要指定公鑰,每次用 ssh 連接的時候也要指定簽名的密鑰(如:增加 -i mymac 指定)。
還會讓你輸入私鑰短語,有的話安全點。

之后運行下面語句將公鑰傳到虛擬機上:

ssh-copy-id -i mymac.pub  myUbuntu

-i后面跟的是對應的公鑰,如果創建密鑰的時候用了非默認名字,這里就要指定。
然后運行:

ssh -i mymac myUbuntu 

實現免密登錄。但是這里如果創建密鑰對的時候輸入了密鑰的短語,還是要輸入短語的,想要每次連接連短語也不輸入的話,可以運行:

ssh-add ~/.ssh/mymac

來輸入短語后緩存,之后連接就不用再輸入額外的信息了。

nginx 配置

安裝 nginx:

sudo apt-get install nginx

/etc/nginx/nginx.conf 就是 nginx 的配置文件,不過一般不將我們的網站的配置放在這里,而是在 /ect/nginx/sites-available 文件夾下,該文件夾下面初始有個演示的例子的配置文件 default,內容如下:

##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name _;
        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #       include snippets/fastcgi-php.conf;
        #
        #       # With php7.0-cgi alone:
        #       fastcgi_pass 127.0.0.1:9000;
        #       # With php7.0-fpm:
        #       fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #       deny all;
        #}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#       listen 80;
#       listen [::]:80;
#
#       server_name example.com;
#
#       root /var/www/example.com;
#       index index.html;
#
#       location / {
#               try_files $uri $uri/ =404;
#       }
#}

# 后面是注釋掉的內容,注釋掉的內容很多是 nginx 的標準配置方法,去掉注釋的內容后實際內容如下:

server {
        # 默認監聽本機80端口
        listen 80 default_server;
        listen [::]:80 default_server;

        # 指名 html 文件夾所在
        root /var/www/html;

        # 網站主頁
        index index.html index.htm index.nginx-debian.html;

        # 訪問的網址
        server_name _;

        # 路由詳細配置
        location / {
                try_files $uri $uri/ =404;
        }
}

我們可以通過拷貝默認配置文件再在上面修改成我們想要的配置,拷貝命令(假設要配置的網站是 example.com ):

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com

修改配置成:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/example.com/html; # 自建的 html 的文件夾位置
    index index.html index.htm; # 該文件夾下要有其中一個文件可以當主頁

    server_name example.com www.example.com; # 只是好看的網址,之后會說

    location / {
        try_files $uri $uri/ =404;
    }
}

這里要注意的是 server_name 后面跟的網址,如果像上面寫的那樣要修改 /etc/hosts 文件,該文件是本機訪問的網站的名稱和 ip 的映射,要用 example.com 這個域名來訪問你的網址(本機訪問,也就是虛擬機訪問,好像這里并沒什么用,因為這個虛擬機沒有瀏覽器,好像還是要通過主機的瀏覽器訪問虛擬機的 ip 來訪問網站,不太懂)就要在 /etc/hosts 文件里加上一行,大概是這樣的:

127.0.0.1 localhost
127.0.0.1 example.com

這樣說起來直接寫 server_name 127.0.0.1更方便。

保存該配置文件后啟動或重啟 nginx 后,主機可以通過訪問虛擬機的 ip 來查看網站了,比如之前設置的是 192.168.56.101,那直接訪問 192.168.56.101 就可以看到你指定的網站的主頁了。

nginx 啟動命令: sudo service nginx start
nginx 重啟命令: sudo service nginx restart
查看 nginx 目前情況: ps -ef | grep nginx

單向驗證的網站

要讓這個網站變成 https 的網站要生成自己的 SSL 證書, 創建放證書的文件夾(之后配置文件里要寫明證書位置,放在某個地方比較方便管理而已):

sudo mkdir /etc/nginx/ssl

生成證書:

sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/nginx/ssl/example.key -out /etc/nginx/ssl/example.crt

生成的時候會問一些問題,按描述填寫就行。問題像這樣:

Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Beijing
Locality Name (eg, city) []:BJ
Organization Name (eg, company) [Internet Widgits Pty Ltd]:my company
Organizational Unit Name (eg, section) []:tech
Common Name (e.g. server FQDN or YOUR name) []:cxswow
Email Address []:

生成的 example.crt 就是證書文件,example.key 是私鑰。

然后把配置文件修改成:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        listen 443 ssl; # 新增加,ssl 默認監聽的端口就是443,開啟監聽

        root /var/www/example.com/html;
        index index.html index.htm;

        server_name  example.com www.example.com;
        ssl_certificate /etc/nginx/ssl/example.crt; # 新增,聲明證書
        ssl_certificate_key /etc/nginx/ssl/example.key; # 新增,聲明私鑰

        location / {
                try_files $uri $uri/ =404;
        }
}

重啟 nginx : sudo service nginx restart
然后訪問網站,這時候就是走的 https 。

雙向驗證的網站

雙向驗證最少要有三方,像是甲方、乙方、見證人這樣的。這里一般叫 server、client、CA 。

之前單向驗證只生成了 server,而且 server 的證書是自己給自己簽名的,這里的 server 證書和 client 證書都要 CA 來簽發,之前的證書不能用了。

所以 server 和 client 生成私鑰和證書簽名請求文件(Certificate Signing Request):

# 生成 server 的私鑰和證書簽名請求文件,還是放在之前說的 /etc/nginx/ssl 文件夾里面,這里進入該文件夾執行下面的命令
sudo openssl genrsa -des3 -out server.key 1024
sudo openssl req -new -key server.key -out server.csr

# 生成 client 的私鑰和證書簽名請求文件
sudo openssl genrsa -des3 -out client.key 1024
sudo openssl req -new -key client.key -out client.csr

# 生成 CA 私鑰和自簽名證書
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout ca.key -out ca.crt

然后生成 ca 認證的 server 證書和 client 證書:

# ca 簽發 server 證書
sudo openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

# ca 簽發 client 證書
sudo openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

而客戶端證書要用在瀏覽器上,一般要轉換成瀏覽器可以用的格式,這里轉成 .p12 格式:

openssl pkcs12 -export -inkey client.key -in client.crt -out client.p12

這里會讓你輸入密碼,是在證書導入瀏覽器的時候要輸入的密碼。

p12 格式的文件在主機上知己雙擊運行安裝就行。

修改 nginx 的配置文件,對虛擬機上部署的 server 進行反向代理:

server {
        # 開啟
        ssl_verify_client on;
        ssl_client_certificate /etc/nginx/ssl/ca.crt;
        ssl on;
        listen 443 ssl default_server;

        # Add index.php to the list if you are using PHP
        #index index.html index.htm index.nginx-debian.html;

        server_name example.com www.example.com;
        ssl_certificate /etc/nginx/ssl/server.crt;
        ssl_certificate_key /etc/nginx/ssl/server.key;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;

                proxy_pass http://localhost:8080/;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                # 當客戶端證書認證通過后,將客戶端證書中 Common Name 提取到 X-ClientCert-DN 頭里
                # 這樣上游的 Node.JS Server 就可以從這里知道登錄用戶的身份了(名字)
                proxy_set_header X-ClientCert-DN $ssl_client_s_dn;
        }
}

這里 proxy_pass 就是別人訪問虛擬機的默認443端口會返回的請求內容,這里要返回本機8080端口的內容,要另外自己開個 server 監聽8080端口。

在主機上安裝 client.p12 證書(雙擊文件可以直接安裝),再訪問 https://192.168.56.101 的時候就可以選擇 client.p12 證書來進行驗證了。

8080端口的那個 server 也可以根據請求頭的 Common Name 來返回不同的內容。

參考:

Guest Additions
File permission issues with shared folders under Virtual Box
VirtualBox 中 ubuntu 的網絡設置
SSH原理與運用(一):遠程登錄
How To Set Up Nginx Server Blocks (Virtual Hosts) on Ubuntu 14.04 LTS
How To Create an SSL Certificate on Nginx for Ubuntu 14.04
Protect your Node.js API with nginx and SSL client certificates
反向代理

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 配置運行Nginx服務器用戶(組) 用于配置運行Nginx服務器用戶(組)的指令是user,其語法格式為: use...
    吃瓜的東閱讀 4,547評論 0 41
  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx?那么一定聽過它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,803評論 24 1,002
  • 上一篇《WEB請求處理一:瀏覽器請求發起處理》,我們講述了瀏覽器端請求發起過程,通過DNS域名解析服務器IP,并建...
    七寸知架構閱讀 81,268評論 21 356
  • 小時候,只知道家里不斷在還債.父母并沒有什么文化,只能從事體力勞動,那個時候父親還在當地的煉鋼廠子里工作,兩班倒的...
    小冰_1118閱讀 359評論 0 0