欢迎,来自IP地址为:98.81.24.230 的朋友
IPv4地址的稀缺,使从主机服务提供商那里获得IP址变得越来越困难和昂贵了,即便是公共云服务商也变得十分吝啬。在我们苦等IPv6地址到来的时候,其实也有一些办法来扩展使用现有IPv4地址空间。
IPv6的一些缺点我也不再一一列举,但是让其真正普及的障碍是全球许多ISP运营商还不想为用户提供IPv6的地址。这点在一些国家尤其严重,IPv6网络一直处于实验网阶段,没有真正向公众用户开放。
其实对于运营商来说,给每个用户分配IPv6地址就像噩梦一般,而用户往往会要求运营商给自己所有的联网设备都分配不同的IPv6地址,这种工作量对于IPv4地址分配来说可以是线性的增加。
依目前的形势来看,在可预见的未来,Web服务业务将继续采用IPv4地址。由于大多数人还没有实现IPv6的接入,并且可能会持续很长一段时间。现在要做的就是如何充分利用越来越稀缺的IPv4地址。
反向代理服务
要理解反向代理,首先需要了解一下地址转换(NAT)。NAT方式打破了端到端的网络模型,这对于IPv6来说简直是种可怕的事情。端到端模型是一种主机A到主机B之间直接通过IP地址互通的方式,中间不存在转换层。端到端方式主机的IP 地址应该都具有公网IP地址,以尽可能减少通信时受到的影响。
NAT方式恰恰相反,NAT方式将整个网络置于同一IP下,通过不同的端口来区分服务器。例如,你想通过RDP远程桌面工具访问一台服务器的3389端口,可能会将该端口映射到公网IP的33389端口。这样,连接此服务器时就要采用rdp.example.com:33389(假设公网IP对应域名example.com)而不是rdp.example.com。
开发人员之前一直在处理NAT的网络中进行编码开发,并没有真正关心过两台主机是如何实现互通的。并且在NAT网络技术基础上开发了大量的程序库,这看起来有些可怕。
如同IPv6纯粹主义者憎恨NAT一样,我们同样可以想像的到他们同样厌恶反向代理,但是反向代理技术是未来发展方向。反向代理服务器在一个IP地址上接收所有的流量,并为相将不同的流量引入不同的后端服务器为其服务。这种方式大量应用于HTTP和HTTPS流量。
HTTP和HTTPS流量包含一个主机头信息(对于HTTPS来说是Server Name Indication (SNI)),这个头信息包含了要访问服务器的信息。除了简单的采用IP地址访问,我们还可以采用域名访问服务器。反向代理服务器会识别不同的主机头信息,根据其配置信息,将不同的流量传递给后端不同的服务器。
网站反向流量代理一般还具有静态内容缓存功能,以加快后端服务器内容的访问速度。反向代理也越来越多的应用于防止服务侦测和内容侦测。同时,还具有一个个人很喜欢的功能,就是为那些不采用SSL技术的网站提供一个统一的SSL前端,以达到网站HTTPS化的目的。后端的WEB服务器可以是任意类型,我们可以使用nginx来提供HTTP反向代理。
商业反向代理当然是有的,Citrix NetScaler VPX是其中一款,当然Barracuda NG Firewall也行,Smoothwall UTM Untangle也具备相应功能。可以说现存的反向代理软件比HTTP服务器可能还要多,但是我们还是选择nginx,因为它是免费、开源和最流行的。
实例讲解
反向代理似乎令人望而生畏,但它实际上并不像想像的那么可怕。我花了几天时间就配置好了一个基于CentOS 7.0的反向代理服务器,以下将是一些基本内容。(这里假定你具有一定的RHEL系列Linux系统使用能力,包括安装、登录及使用vim及yum工具)。
1、最小化安装CentOS 7.0,关闭SELinux,安装相应软件和设置目录:
yum install epel-release yum install net-tools wget python nginx git yum update mkdir /var/www/nginx_cache mkdir /var/www/nginx_tmp mkdir /var/www/letsencrypt-auto chown nginx:nginx /var/www/nginx_cache chown nginx:nginx /var/www/nginx_tmp chown root:root /var/www/letsencrypt-auto chmod 0755 /var/www/nginx_cache chmod 0755 /var/www/nginx_tmp chmod 0755 /var/www/letsencrypt-auto
2、将/etc/nginx/nginx.conf的配置文件替换为如下内容:
user nginx; worker_processes 2; worker_rlimit_nofile 2048; error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; multi_accept on; use epoll; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; # Proxy cache and temp configuration. proxy_cache_path /var/www/nginx_cache levels=1:2 keys_zone=main:10m max_size=1g inactive=30m; proxy_temp_path /var/www/nginx_tmp; # Gzip Configuration. gzip on; gzip_disable msie6; gzip_static on; gzip_comp_level 4; gzip_proxied any; gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; include /etc/nginx/mime.types; default_type application/octet-stream; client_max_body_size 100m; # Report real IPs from X-Forwarded-For header from Cloudflare IPs set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 104.16.0.0/12; set_real_ip_from 108.162.192.0/18; set_real_ip_from 131.0.72.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 162.158.0.0/15; set_real_ip_from 172.64.0.0/13; set_real_ip_from 173.245.48.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 190.93.240.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; set_real_ip_from 199.27.128.0/21; set_real_ip_from 2400:cb00::/32; set_real_ip_from 2606:4700::/32; set_real_ip_from 2803:f800::/32; set_real_ip_from 2405:b500::/32; set_real_ip_from 2405:8100::/32; set_real_ip_from 2c0f:f248::/32; set_real_ip_from 2a06:98c0::/29; real_ip_header CF-Connecting-IP; # Load modular configuration files from the /etc/nginx/conf.d directory. include /etc/nginx/conf.d/*.conf; }
3、创建/etc/nginx/conf.d/servers.conf配置文件或修改成如下内容:
server { listen 80; server_name example.com www.example.com; access_log /dev/null; # Allows letsencrypt-auto to verify domain ownership location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; allow all; root /var/www/letsencrypt-auto; } proxy_ignore_headers "Cache-Control" "Expires"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 100m; proxy_pass_header Set-Cookie; # Catch the wordpress cookies. # Must be set to blank first for when they don't exist. set $wordpress_auth ""; if ($http_cookie ~* "wordpress_logged_in_[^=]*=([^%]+)%7C") { set $wordpress_auth wordpress_logged_in_$1; } # Set the proxy cache key set $cache_key $scheme$host$uri$is_args$args; # Don't cache these pages. location ~* ^/(wp-admin|wp-login.php){ proxy_pass http://examplebackend; } location / { proxy_pass http://examplebackend; proxy_cache_bypass $cookie_nocache $arg_nocache; proxy_cache main; proxy_cache_key $cache_key; proxy_cache_valid 30m; # 200, 301 and 302 will be cached. # Fallback to stale cache on certain errors. # 503 is deliberately missing, if we're down for maintenance # we want the page to display. proxy_cache_use_stale error timeout invalid_header http_500 http_502 http_504 http_404; # 2 rules to dedicate the no caching rule for logged in users. proxy_cache_bypass $wordpress_auth; # Do not cache the response. proxy_no_cache $wordpress_auth; # Do not serve response from cache. }
如果你想缓存内容,则采用如下配置
# Backend server definition upstream examplebackend { server 172.16.0.199; } server { listen 80; server_name example.com www.example.com; # Allows letsencrypt-auto to verify domain ownership location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; allow all; root /var/www/letsencrypt-auto; } proxy_ignore_headers "Cache-Control" "Expires"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 100m; proxy_pass_header Set-Cookie; # Catch the wordpress cookies. # Must be set to blank first for when they don't exist. set $wordpress_auth ""; if ($http_cookie ~* "wordpress_logged_in_[^=]*=([^%]+)%7C") { set $wordpress_auth wordpress_logged_in_$1; } # Set the proxy cache key set $cache_key $scheme$host$uri$is_args$args; location / { proxy_pass http://examplebackend; proxy_cache_valid any 0; }
这些配置文件被设计成WordPress兼容的,因为我的网站目前采用了此方式建设。
为后端的每台服务器都添加一个配置文件块,如果后端服务器对应多个网站,则只需要为主机添加不同的域名。如果想配置成缓存和非缓存混合结构,这看起来很不错,你可以配置足够的文件块来指向你后端的服务器。这里留下了一些配置内容给朋友们练习,我想以上的注释内容可以帮助完成配置。
最后还要在你的互联网出口设备上开一个端口,以便网络访问。确保公网IPv4地址的80端口可以被nginx侦听,完成此步骤后,你便拥有了一台全功能的反向代理服务器。
下面便是启用letsencrypt功能以进行SSL的配置,下面就是安装letsencrypt。
4、启用SSL功能配置
以下的操作假定使用root用户操作,首先安装letsencrypt:
$ cd ~ $ git clone https://github.com/letsencrypt/letsencrypt $ cd letsencrypt $ ./letsencrypt-auto
也许会出现“no installers are available on your OS yet; try running ‘letsencrypt-auto certonly’ to get a cert you can install manually”的提示,这也没有什么关系,忽略就是了。现在我们为openssl生成一个良好的密钥,由于要一直使用,当然选择加密位数较高的,可能花费的时间有点久,耐心等就是了。
$ cd /etc/nginx $ openssl dhparam -out dhparam.pem 4096
一旦这步完成,便可以在/root/letsencrypt目录中创建一个叫作letsencrypt_gen的脚本文件,内容如下:
#!/usr/bin/env bash if [[ -z "$DOMAINS" ]]; then echo "Please set DOMAINS environment variable " \ "(e.g. \"-d example.com -d www.example.com\")" exit 1 fi if [[ -z "$DIR" ]]; then export DIR=/var/www/letsencrypt-auto fi mkdir -p $DIR && /root/letsencrypt/letsencrypt-auto certonly -v \ --server https://acme-v01.api.letsencrypt.org/directory \ --webroot \ --webroot-path=$DIR \ $DOMAINS service nginx reload
创建完成后,用命令chmod 0755将该脚本的权限设置为可执行。然后运行此脚本以生成letsencrypt的证书文件:
$ cd ~/letsencrypt $ DOMAINS="-d example.com -d www.example.com" \ /root/letsencrypt/letsencrypt_gen
假设域名使用example.com,也就是指向nginx服务器域名序列的第一个域名。操作完成后,会在/etc/letsencrypt目录生成相应文件。现在需要在nginx的配置文件中增加相应内容以开启SSL:
server { listen 443 ssl; server_name example.com www.example.com; # certificates from letsencrypt ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; # Diffie-Hellman parameter for DHE ciphersuites ssl_dhparam /etc/nginx/dhparam.pem; # modern configuration 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:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK'; ssl_prefer_server_ciphers on; # HSTS (ngx_http_headers required) - 6 months # add_header Strict-Transport-Security max-age=15768000; # OCSP stapling ssl_stapling on; ssl_stapling_verify on; # verify chain of trust of OCSP response ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem; proxy_ignore_headers "Cache-Control" "Expires"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 100m; proxy_pass_header Set-Cookie; # Catch the wordpress cookies. # Must be set to blank first for when they don't exist. set $wordpress_auth ""; if ($http_cookie ~* "wordpress_logged_in_[^=]*=([^%]+)%7C") { set $wordpress_auth wordpress_logged_in_$1; } # Set the proxy cache key set $cache_key $scheme$host$uri$is_args$args; location / { proxy_pass http://examplebackend; proxy_cache_valid any 0; }
完成后,重新启动nginx,开启外网相应端口(443)。
由于letsencrypt的证书一般只有90有效期,所以要在证书失效前重新更新证书。可以使用cron命令自动设置更新证书功能/root/letsencrypt/certbot-auto renew。
现在,你的反向代理服务器便可以对example.com的SSL请求做出响应了,然后将非SSL请求传递至后端服务器。不必为后端的每台服务器都应用SSL功能,也不必购买证书。现在,你就以一个IP地址运行了多台虚拟服务器,并且每台服务器都可以是自动更新SSL证书。
应对稀缺资源
在不久之前,每个SSL站点都需要独立的IP地址,但现在SNI(Server Name Indication)技术改变了这一状况。仿佛一下了我们可以使用30个地址一样,而在10年前,同时拥有30个地址很容易受到限制的。
反向代理只有应对IPv4地址枯竭的一种技术手段之一,在采用纯端到端IPv6技术之前,我们采用此类技术可以有效的使用现有IPv4地址,从而延长其使用寿命。
诚然,我们现有没有更多的IPv4地址可以分配了,但这差不意味着我们不能再使用IPv4地址了。我们会变得更加聪明,以保证我们在没有更多IPv4地址的情况部署更多的公众应用。
同时,反向代理和下一代防火墙将有效的延长现有IPv4地址的使用期,同时,所涉及的技术也真的没有那么复杂。