起因

之前购买的科学上网帐号到期了,考虑到网络数据安全性的问题,决定购买一台 VPS 搭建梯子。比较了 DigitalOceanBandwagonLinode 之后,因为 Linode 界面清晰简单,口碑也比较好,于是就选用了 Linode。然而即使是最便宜的一台 VPS 每个月也有 2TB 的流量以及 30GB 的存储容量,所以决定还是搭建一个博客用来记录学习和生活(现在最便宜的是 1TB 容量和 20GB 存储了,当然价格也只有一半)。

VPS

创建 VPS

正如起因里说的,我选择的是 Linode $10/m 的套餐,登录:

https://linode.com

创建帐号,然后添加一个 linode

选择一个合适的套餐和 VPS location 并点击 Add this Linode!, 创建成功则会自动跳到管理页面:

点击刚创建出来的 linode2789965Linode 会自动初始化这个 VPS,但这时候它还仅仅是一台「裸机」,所以我们还需要给它安装操作系统。

点击 Deploy an Image,选择一个合适的操作系统:

这里,我选择的是 Debian 8 操作系统,你可以根据自己的需求选择合适的操作系统。其他的设置保持默认,然后设置 root password,最后点击 Deploy

这时候一台全新的可以 ssh 连接上去的 VPS 就算成功创建了。但此时它依然是未启动的。回到它的 Dashboard,点击 Boot,然后一会儿就创建成功了。

by the way

如果你也想购买 Linode 的 VPS,可以点击这里,链接里包括了我的 referral code :)。如果你更想使用 Vultr,可以点击这里

SSH 登录

现在,想要登录刚才创建出来的 VPS 非常简单,在终端里输入:

$ ssh root@ip

ip 也就是创建完 VPS 后分给你的 ip,根据提示输入密码,连接成功的话就顺利地登入到 VPS 了。

然而这种方式登录每次都需要输入密码很浪费时间,比较方便的方式就是用公钥登录这种方式。

引用阮一峰老师的博客

所谓”公钥登录”,原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

要获取公钥最简单的方法就是在终端里输入:

$ ssh-keygen

根据提示设置公钥和私钥的存储位置和文件名,默认情况下,这个命令会在 $HOME/.ssh/ 目录下生成名为 id_rsa.pub 的公钥和对应的名为 id_rsa 的私钥。

这时再输入以下命令,将刚才生成的公钥上传到 VPS 上:

$ ssh-copy-id -i id_rsa.pub root@ip

然后就可以无需密码登录 VPS 了。至于 ssh 的使用或者碰到问题,可以参考阮一峰老师的博客。

域名

域名的作用就不用说了,具体说说购买域名以及设置的一些具体流程。这里我选择的是 GoDaddy

https://godaddy.com

注册帐号后选择你想要且没有被别人注册的域名添加到购物车,然后付款:

DNS 设置

由于我是在 Linode 购买的 VPS,而域名是在 GoDaddy 网站购买,所以我想要让 Linode 来管理这个域名的 DNS。登录 Linode 网站,点击 DNS Manager

Linode 的 DNS 管理是用一个叫 Domain Zone 的概念来描述的,官方是这么形容 Domain Zone的:

a container for DNS records associated with a single domain name.

也就是说 Domain Zone 就是一个用来管理单条域名 DNS 记录的容器。

添加一个新的 Domain Zone

如果之前没有设置过任何 Domain Zone 信息,那么默认这个页面会直接显示添加或导入一个 Domain Zone 信息。(由于我已经添加过,所以这里列出了我添加的记录)。

填写域名和邮箱并选择根据你刚才创建的 linode 创建默认的记录,然后点击 Add a Master Zone

创建成功,就会根据你的 VPS 的信息自动生成一系列记录,包括邮件服务 MX RecordsA 记录

回到 GoDaddy,并点击右上角用户名选择我的产品

然后选择刚才注册的域名并点击管理 DNS

选择自定义域名服务器并更改:

填写 Linode 的几个域名服务器并保存:

至此,域名就已经和你 VPS 的 ip 绑定了,最多 24-48 小时后就可以通过域名访问你的 VPS。(然而你的 VPS 上目前并没有提供 Web 服务,所以访问后看到的应该也是一片空白)。

Jekyll

选择与安装

创建好了 VPS,购买了域名并且绑定了 DNS,下面就可以开始选择搭建一个博客系统了。由于我只想要一个输出静态内从的博客,所以 WordPress 就不在我的考虑范围了。搜索了一下发现目前大部分个人博客比较好的选择就是 GhostHexoJekyll。其中,GhostHexo 都是基于 Node.js 写成,Jekyll 基于 Ruby 写成,由于我对 Javascript 不是很熟悉并且在 macOS 上默认已经安装了 ruby 2.0.0p648, 所以最后我选择了 Jekyll 来搭建这个博客。

http://jekyllrb.com/docs/quickstart/

按照 quick-start guide 安装 Jekyllbundler

# Install Jekyll and Bundler gems through RubyGems
~ $ gem install jekyll bundler

# Create a new Jekyll site at ./myblog
~ $ jekyll new myblog

# Change into your new directory
~ $ cd myblog

# Build the site on the preview server
~/myblog $ bundle exec jekyll serve

# Now browse to http://localhost:4000
权限问题及 SIP

如果提示权限问题,在命令前添加 sudo。由于 macOS10.11 起添加了 System Integrity Protection 保护,导致可能即使用 sudo 也无法安装,可以根据这篇文章关闭 SIP 保护。

bundler

至于 bundler,它的作用就是用来管理项目引入的第三方库的,类似于 iOS 开发里的 Cocoapods,事实上,Cocoapods 就是受 bundler 启发而来,所以无论从配置文件的格式还是命令的参数上,Cocoapodsbundler 几乎一样。

发布

http://jekyllrb.com/docs/deployment-methods/

由于 Jekyll 生成的是静态页面的博客,所以只要将生成的 _site 文件夹发布到可以被访问的服务器上就可以。因此,Jekyll 文档里描述了多种发布方式,由于我使用 git 管理这个博客项目并且想要将博客部署到我的 VPS 上,所以我选择 Git post-receive hook 这种方式。

首先,登录到 VPS 上并安装 Ruby 及相关环境:

server$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
server$ \curl -sSL https://get.rvm.io | bash -s stable

rvmRuby Version Manager 的缩写,是一个可以方便你在一台电脑上安装、管理 rubyruby gem 的工具。

现在,你已经有了一个可以运行的 ruby 虚拟机了,接着:

server$ gem install jekyll

在 VPS 上安装一个 Jekyll 是为了下面的操作。

然后创建一个 git 裸仓库(bare repo):

server$ mkdir myrepo.git
server$ cd myrepo.git
server$ git --bare init
server$ cp hooks/post-receive.sample hooks/post-receive
server$ cd && mkdir blog_site

由于用 git --bare init 创建出来的 git 仓库没有 workspace,因此绝大多数的 git 命令都无法直接在这个目录下操作,这个特性十分适合用来创建一个中心仓库,我们只需要 push 代码到这个仓库下并且利用 git post-receive hook 特性就可以十分方便地实现:push 代码到仓库后自动生成新的网页代码

编辑 ~/myrepo.git/hooks/post-receive:

GIT_REPO=$HOME/myrepo.git
TMP_GIT_CLONE=$HOME/tmp/myrepo
PUBLIC_WWW=$HOME/blog_site

git clone $GIT_REPO $TMP_GIT_CLONE
jekyll build -s $TMP_GIT_CLONE -d $PUBLIC_WWW
rm -Rf $TMP_GIT_CLONE
exit

这个文件就是一个 shell 脚本,主要用途就是当收到新 push 过来的代码时,自动调用 jekyll 构建网站页面。

其他方式

当然,如果不想在 VPS 上安装 rvmrubyJekyll 等环境,可以选择直接将生成好的 _site/ 目录通过 scp 命令直接上传到 VPS 上,限于篇幅太长,暂时不说了。

Nginx

虽然通过上面的步骤我们已经成功的将本地机器的博客文章上传到 VPS 并且使用 Git post-receive hook 生成网页,但目前来说还不能通过访问域名的方式来访问你的博客。接下来我们将使用 Nginx 作为我们的 Web ServerJekyll 自带 Webrick Server,可以直接在 VPS 上通过 Jekyll serve 命令构建网站供用户访问,但是 Webrick 的性能以及接下来要用到的 HTTPS 配置促使我选择了 Nginx 作为我博客的服务器)。

安装

server$ apt-get update
server$ apt-get install nginx
server$ service nginx start

直接在浏览器里输入 VPS 的 IP 地址,应该就可以看到 Welcome to Nginx, 或者:

server$ service nginx status

应该可以看到 [ ok ] nginx is running.

接下来,配置 Nginx 使得它指向刚才创建出来的目录:

server$ nano /etc/nginx/sites-enabled/default

找到 root /var/www/html 这一行修改成:root /home/your_username/blog_site

接着,找到 server_name your_domain.com,用你注册的域名替换 your_domain.com

然后:

server$ nginx -s reload

这时候,通过域名应该就可以看到能访问博客了!

HTTPS

虽然这只是一个静态博客,但由于 Google 降低了未支持 HTTPS 网站的收录权重,所以我还是想要给我的网站添加 HTTPS 支持。

现在有很多免费提供 HTTPS 认证的网站,最知名的应该就属 Let‘s Encrypt 了,它提供最长时间为 90 天的免费 TLS 证书,并且它支持标准的 ACME(Automatic Certificate Management Environment)协议,这使得我们可以方便的使用脚本来管理证书的生成与部署,所以,虽然每一个证书只有 90 天的有效时间,但通过 cron job 我们可以在证书有效期即将到来时自动重新生成新的证书并部署,相当于有了无限期免费的 TLS 证书(由于一个证书的有效期是 90 天,所以很明显它不适合用做 public key pinning)。

目前已经有多种语言编写的脚本用来自动化生成和部署 Let's Encrypt 证书:

https://letsencrypt.org/docs/client-options/

我选择了 acme.sh 这个 bash 脚本。

https://github.com/Neilpang/acme.sh

这个脚本使得生成和部署证书变得十分简单。首先,在服务器上获取并安装这个脚本(执行这个脚本最好是用 root 账户):

server$ curl https:/get.acme.sh | sh

这条命令主要做了以下几件事:

  1. 下载 acme.sh 命令到本地目录
  2. 创建一个隐藏目录 $HOME/.acme.sh, 这个目录也是后面生成的证书文件所存放的位置
  3. 创建一个 alias 方便你使用这个脚本
  4. 创建一个 cron job 来定期执行这个脚本,用来重新生成新的证书(如果快到期的话)

目前来说,执行了上面的命令依然还是没有证书生成的,所以第一次需要你手动生成,根据文档,我选择了 DNS API Mode

https://github.com/Neilpang/acme.sh/tree/master/dnsapi

因为我用的是 Linode 服务器,所以根据文档,到 Linode 服务器上创建一个你的 API Key,然后:

server$ export LINODE_API_KEY="你刚才创建出来的 api key"

然后执行:

server$ acme.sh --issue --dns dns_linode --dnssleep 900 -d example.com -d www.example.com

由于 DNS 服务器记录更新时间的原因,这里默认设置了一个 900 秒的等待时间,等待 Linode DNS 更新。如果没有问题的话,900 秒后 Let's Encrypt 就会成功认证你的网站并签发证书。

安装证书

将刚才生成的证书安装到 Nginx 配置目录下:

server$ acme.sh --install-cert -d example.com \
--keypath       /etc/nginx/ssl/mydomain.key  \
--fullchainpath /etc/nginx/ssl/mydomain.cer \
--reloadcmd     "service nginx force-reload"

修改 Nginx 配置

如果 TLS 证书成功生成,那么我们需要修改 Nginx 配置来使证书生效:

server$ nano /etc/nginx/sites-enabled/default

修改其中的配置为:

server {
        listen 80;
        server_name example.com;
        return 301 https://$host$request_uri;
}

server {
        listen 443 ssl;
        server_name example.com;

        ssl_certificate /etc/nginx/ssl/mydomain.cer;
        ssl_certificate_key /etc/nginx/ssl/mydomain.key;

        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_dhparam /home/deploy/dhparams.pem;


        root /home/your_username/blog_site;

        index index.html index.htm index.nginx-debian.html;
        
        location / {
                try_files $uri $uri/ =404;
        }
        
}

主要修改的目的是指定证书文件的存放目录和将 80 端口收到的请求都永久重定向到 443 端口,这样,当你输入 http://domain.com 就会被重定向到 https://domain.com

接着 reload Nginx 配置:

server$ nginx -s reload

输入你的域名试试看是否可以访问了!

博客主题(theme)

Jekyll 默认的主题叫 minima,是一个很简单的样式,可以在博客所在的目录下输入:bundle show minima 查看 minima 所安装的位置。

我最后选择的这个主题是 leonids,只需要简单地 clone 到本地就可以使用了。

其他

这篇博客就是用来记录这个博客的诞生,很多东西都是很少弄,所以记录下来免得以后忘了又得 google 一番。。。难免有疏漏,欢迎评论。

参考