使用 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
反向代理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 配置运行Nginx服务器用户(组) 用于配置运行Nginx服务器用户(组)的指令是user,其语法格式为: use...
    吃瓜的东阅读 4,478评论 0 41
  • 第一章 Nginx简介 Nginx是什么 没有听过Nginx?那么一定听过它的“同行”Apache吧!Ngi...
    JokerW阅读 32,637评论 24 1,002
  • 上一篇《WEB请求处理一:浏览器请求发起处理》,我们讲述了浏览器端请求发起过程,通过DNS域名解析服务器IP,并建...
    七寸知架构阅读 80,921评论 21 356
  • 小时候,只知道家里不断在还债.父母并没有什么文化,只能从事体力劳动,那个时候父亲还在当地的炼钢厂子里工作,两班倒的...
    小冰_1118阅读 328评论 0 0