这篇文章是我的 Linux 操作系统课大作业(PPT 材料)。发在这里是供自己和大家参考,如有错误或不当敬请指正。
从官方源安装 Nginx
安装 Nginx 其实很简单。
大多数的 Linux 发行版自带的源已经包含 Nginx。因此只需要一行命令:
apt install nginx
(或 yum install nginx
等,取决于你的发行版,这里以 Debian 系列为例)
但是,如果发行版比较老,自带的 Nginx 也是旧版本的,会缺乏新特性支持。为了配置安全又快速的网站,我们需要用到一些现代特性,因而需要自己编译。
三个现代特性
我们主要会用到这些现代特性:
HTTP/2
目前 HTTP 协议最新一代。正式版发布于 2015 年 5 月。前身是 SPDY 协议,包含多路复用等提升网页加载速度的技术。Nginx 从 1.9.5 开始官方支持(http_v2_module 取代 ngx_http_spdy_module)。建议使用更新版本避免早期实现的小 BUG。
Brotli
Google 推出的无损压缩算法,对常见静态资源有更高的压缩率。“当 Brotli 压缩级别为 1 时,压缩率比 Gzip 压缩等级为 9(最高)时还要高”。Nginx 官方未提供内置模块,需要自行编译置入。
参考资料:《启用 Brotli 压缩算法,对比 Gzip 压缩 CDN 流量再减少 20%》
注:由于兼容性及其他原因,HTTP/2 与 Brotli 事实上只工作于 HTTPS 环境下。
TLS 1.3
目前 TLS 最新的标准。经历了几次草案,正式版发布于 2018 年 8 月。相较于旧版本大幅改进了性能和安全性。Nginx 从 1.13.0 开始提供支持。建议使用更新版本避免早期实现的 BUG,并且增加对 Early Data 的支持(Nginx 1.15.4 起)。需要配合 OpenSSL 1.1.1 版本才能开启 TLS 1.3(由于该 OpenSSL 过新,通常意味着需要手动编译)。
参考资料:《SSL/TLS 历史与前沿导览》
结论
综上,我们的最佳选择其实是使用最新版本的 Nginx。
截至本人撰写该材料,Nginx 的最新主线版本是 1.17.0,以下均以此版本展开。
编译安装 Nginx
为了避免手动新建用户,撰写 Service 文件等的麻烦,我们先从官方源安装 Nginx,再手动编译 Nginx。但在编译 Nginx 本体之前,我们先安装相关开发工具的依赖。以下操作均以 root 身份进行。
apt install autoconf libtool automake perl make gcc g++ patch git zlib1g-dev libxslt-dev libgd-dev geoip-database libgeoip-dev
下载最新版本的 OpenSSL 以提供 TLS 支持。暂时不需要编译,稍后会与 Nginx 一同编译。
mkdir /usr/local/openssl
cd /usr/local/src
wget https://www.openssl.org/source/openssl-1.1.1b.tar.gz
tar xzf openssl-1.1.1b.tar.gz
cd openssl-1.1.1b
./config
下载 pcre 源码。这个库提供正则表达式的支持。
mkdir -p /root/nginx-source/pcre
cd /root/nginx-source/pcre
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.42.tar.gz
tar -zxvf pcre-8.42.tar.gz
接着下载 ngx_brotli 源码。
cd ~
git clone https://github.com/eustas/ngx_brotli.git # 这并非 Google 的官方仓库,但相比较版本更新
cd ngx_brotli
git submodule update --init
同很多其他程序一样,Nginx 也采用 Makefile 文件方便用户编译,但我们应该手动配置一些参数再开始编译。
cd /usr/local/src
wget http://nginx.org/download/nginx-1.17.0.tar.gz
tar xzf nginx-1.17.0.tar.gz
cd /usr/local/src/nginx-1.17.0
./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-1.17.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-mail=dynamic --with-mail_ssl_module --with-openssl=/usr/local/src/openssl-1.1.1b --with-pcre=/root/nginx-source/pcre/pcre-8.42 --add-module=/root/ngx_brotli
make
编译后安装只需一句:
make install
因为我们是要替代原有 Nginx 的,所以再进行一些工作:
rm -rf /usr/sbin/nginx # 删除原有 Nginx 程序
ln -s /usr/share/nginx/sbin/nginx /usr/sbin/nginx # 建立软链接
nginx -t # 测试 Nginx 配置文件正确性
nginx -V
service nginx restart
apt-mark hold nginx # 禁止系统自带 Nginx 包更新
可见,这样一来,安装 Nginx 的过程变得麻烦耗时。好在我们其实可以选择用第三方的 Nginx 包。
从第三方源安装 Nginx
SB 仓库(烧饼博客提供)就是一个不错的选择,其网址是:
https://mirror.xtom.com/sb/nginx/ (主站)
https://mirror.xtom.com.hk/sb/nginx/ (香港镜像)
该源使用 OpenSSL 1.1.1 编译,支持 TLS 1.3、GeoIP2、Brotli 压缩等,会保持跟进最新 Nginx 版本,符合我们需求。
于是 Nginx 的安装再次变得简单:
curl https://mirror.xtom.com/sb/nginx/public.key | apt-key add - # 添加源公钥
echo "deb https://mirror.xtom.com/sb/nginx/ stretch main" > /etc/apt/sources.list.d/sb-nginx.list # 添加源
apt update && apt install nginx # 从源安装
Nginx Conf 内容
全局配置
SSL 方面遵循《SSL/TLS 部署最佳实践》(SSL and TLS Deployment Best Practices):
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
ssl_stapling on;
ssl_stapling_verify on;
ssl_prefer_server_ciphers on;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256';
ssl_certificate /yourcert;
ssl_certificate_key /yourkey;
ssl_dhparam /dhparams.pem;
ssl_early_data off;
对于压缩,优先使用 Brotli 压缩,兼容 Gzip:
brotli on;
brotli_comp_level 5;
brotli_min_length 256;
brotli_types text/plain text/javascript text/css text/xml text/x-component application/javascript application/x-javascript application/xml application/json application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types text/plain text/javascript text/css text/xml text/x-component application/javascript application/x-javascript application/xml application/json application/xhtml+xml application/rss+xml application/atom+xml application/x-font-ttf application/vnd.ms-fontobject image/svg+xml image/x-icon font/opentype;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
安全协议头(Headers),根据实际情况配置:https://securityheaders.com/
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # 强制 HTTPS。请务必理解后再添加该头,不容易反悔。
add_header Content-Security-Policy "upgrade-insecure-requests" always; # 内容安全策略,请自行查阅相关资料。
配置默认的 HTTP 和 HTTPS 服务器,以防全网嗅探:
server {
listen 0.0.0.0:80 default_server;
listen [::]:80 default_server;
server_name _;
add_header X-Frame-Options "DENY" always; # 这里又有 add_header,Nginx 会以该区块为准,忽略全局 add_header
return 403;
}
server {
listen 0.0.0.0:443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name _;
ssl_stapling off;
ssl_certificate /your_invalid_crt;
ssl_certificate_key /your_invalid_crt_key;
add_header X-Frame-Options "DENY" always;
return 403;
}
虚拟主机
最后就是各个网站的配置了。例如:
server {
listen 0.0.0.0:80;
listen [::]:80;
server_name www.xuab.net;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
location / {
return 301 https://www.xuab.net$request_uri;
}
}
server {
listen 0.0.0.0:443 ssl http2;
listen [::]:443 ssl http2;
server_name www.xuab.net;
location / {
root /var/www/www.xuab.net;
location ~ ^/.+\.php {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/?.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock; # 这是 Unix Socket,你也可以按实际情况换成普通的 Socket
}
if (!-e $request_filename)
{
rewrite ^(.+)$ /index.php?q=$1 last; # 地址重写,或称“伪静态”
}
}
}
这是以典型 PHP 博客(WordPress)为例。其他场景可能会想要配置反向代理。
效果
可以使用浏览器的开发者工具观察到上述三个现代特性:
(原发于 徐AB 2019-06-10 15:56)
可以在 debian 12的软件源里找到与 brotli 相关的模块,应该可以用命令来安装 https://packages.debian.org/bookworm/libnginx-mod-http-brotli-filter
感谢告知。