CentOS下Nginx的HTTPS配置

在前面的博客里也到了nginx的安装,现在需要给网站添加安全证书的达到可以实现https请求的功能。

1. 首先我们需要一个证书

可以使用自签名的证书(如何自签可以网上搜索下),虽然可以使用但不会被chrome,firefox,Safari等浏览器认可。

也可以去网上购买证书,加个几百元到上万元不等可以自行选择合适价位的证书,不过我在阿里云的购买证书上发现了赛门铁克的0元dv ssl可以使用一年,初次使用推荐去购买一个。

2. nginx的ssl模块安装

安装时直接./configure是不会安装ssl模块的,需要加上

./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module  --with-http_realip_module 
make
make install

3. nginx的ssl配置

添加新的server代码块用来监听443端口

... 

#服务器的集群  
upstream  tomcats {  #服务器集群名字   
   server    127.0.0.1:8080  weight=10;#服务器配置   weight是权重的意思,权重越大,分配的概率越大。  
   #server    127.0.0.1:28080  weight=2;  
}  

server {
     listen     443;
     server_name  www.xxx.com;

     ssl on; 

     ssl_certificate   /usr/local/cert/证书名.pem;
     ssl_certificate_key  /usr/local/cert/证书名.key;
     ssl_session_timeout 5m;
     ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
     ssl_prefer_server_ciphers on;

    location / {
        root html;
        proxy_pass http://tomcats;        
        index index.html index.htm;
    }



}
...

4. 将http重定向到https

server { 
listen 80; 
server_name www.xxx.com;
#添加下面这条代码  
rewrite ^(.*)$  https://$host$1 permanent; #用于将http页面重定向到https页面

  location / {
    root html;
    proxy_pass http://tomcats;
    index index.html index.htm;
}

5. 重启nginx

/usr/local/nginx/sbin/nginx -s reload

Nginx不安全配置可能导致的安全漏洞

前言:

Nginx (engine x) 是一个高性能的http和反向服务器,也可以作为IMAP/POP3/SMTP服务器。t engine是由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。

在渗透测试过程中发现很多网站使用了nginx或者tenginx来做反向代理,ningx的配置文件nginx.conf的一些错误配置可能引发一些安全漏洞。下面是总结的一些可能引发安全问题的错误配置,并且推荐了github上一款用于检测nginx安全配置的工具。

Ningx.conf配置一共分为4部分:1.顶级配置2.Events 模块3.http部分 4.server部分

0×00任意文件读取

这个常见于Nginx做反向代理的情况,动态的部分被proxy_pass传递给后端端口,而静态文件需要Nginx来处理。假设静态文件存储在/home/目录下,而该目录在url中名字为files,那么就需要用alias设置目录的别名:

location /files {
    alias /home/;
}

此时访问http://127.0.0.1:8080/files/1.txt,就可以获取/home/1.txt 文件。

未分类

我们发现,url上/files没有加后缀/ ,而alias设置的/home/是有后缀/的,这个 /就导致我们可以从/home/目录穿越到他的上层目录,造成任意文件下载:

未分类

修复方法:不写成上面那种有漏洞的形式,比如可以写成结尾都带着/字符。

0×01$uri导致的CRLF注入

在实际业务场景中经常需要在nginx中配置路径跳转。

比如用户访问http://x.com 自动跳转到https://x.com 或者是访问 http://x.com 自动跳转到 http://www.x.com

在跳转的过程中,我们需要保证用户访问的页面不变,所以需要从Nginx获取用户请求的文件路径,有三个可以表示uri的变量:

$uri
$document_uri
$request_uri

$uri 和 $document_uri表示的是解码以后的请求路径,不带参数,$request_uri表示的是完整的URI(没有解码),如果在nginx.conf中配置了下列的代码:

location /test {
             return 302 http://$host:81$uri;
                 }

因为$uri是解码以后的请求路径,所以可能就会包含换行符,也就造成了一个CRLF注入漏洞。

未分类

该漏洞除了发生在 return后面,也可能发生在rewrite、add_header、p roxy_set_header、proxy_pass之后。

修复方式:将$uri或者$document_uri改为 $request_uri。

0×02 SSRF

SSRF(服务端请求伪造)漏洞常出现在反向代理的配置中,反向代理的语法如下:proxy_pass http ://IP

如果攻击者可以操控IP, 将其修改成内网IP地址即可造成SSRF漏洞。

0×03目录遍历

autoindex off;#是否开启目录列表访问,默认关闭。

若设置成autoindex on;

未分类

未分类

0x04nginx版本泄露

对于nginx服务器,之前曾爆出过不同版本的解析漏洞,比如nginx 0.7.65以下(0.5.*, 0.6.*, 0.7.* )全版本系列和0.8.37(0.8.*)以下8系列受影响。下面假设在存在漏洞的站点上有一张图片url地址为:http://x.x.x.x/logo.jpg 而当我们正常访问图片时,nginx会把这个当作非脚本语言直接读取传送会客户端(也就是浏览器),但是

存在解析漏洞的nginx会把如下连接解析并且当作php文件执行~:

http://x.x.x.x/logo.jpg/x.php

http://x.x.x.x/logo.jpg%00x.php

因此隐藏 Nginx 的版本号,提高安全性。

在配置文件nginx.conf里面,设置如下:server_tokens off;

未分类

未分类

Nginx配置安全检查的工具

Github上开源了一款Nginx配置安全检查的工具,叫做gixy,可以覆盖以上的部分问题。

项目地址: https://github.com/yandex/gixy

工具是用python编写的,python2.7和3.5+版本都支持。可以直接用pip来安装:pip install gixy。

使用起来也很简单,直接将 gixy 命令后面加上 ningx.conf 文件的具体位置即可。

未分类

nginx的反向代理功能和缓存功能

一、nginx的反向代理功能

1.1 正向代理和反向代理

正向代理是众多内网客户机上网访问互联网上的网站时,将所有的请求交给内网前面处于公网上的”管家”服务器,由”管家”服务器代为请求想要访问的web服务器,然后将得到的结果缓存下来并提供给客户端,这是正向代理。”管家”服务器称为正向代理服务器。

未分类

反向代理是客户端访问web服务器时,请求发送到真实的web服务器的前端”助手”服务器上,由”助手”服务器决定将此请求转发给哪个真实的web服务器,外界客户端以为”助手”服务器就是真实的web服务器,而实际上它不是,也不需要安装任何web程序。”助手”服务器称为反向代理服务器。

未分类

nginx是一个优秀的反向代理服务程序,通过反向代理可以实现负载均衡的效果。因为是通过反向代理实现的负载均衡,所以nginx实现的是七层负载均衡。它能够识别http协议,根据http报文将不同类型的请求转发到不同的后端web服务器上。后端的web服务器称为”上游服务器”,即upstream服务器。

实际上,nginx和php-fpm结合的时候,指令fastcgi_pass实现的也是反向代理的功能,只不过这种代理功能是特定的功能,只能转发给php-fpm。

nginx的反向代理有几种实现方式:

  • 仅使用模块ngx_http_proxy_module实现简单的反向代理。指令为proxy_pass。

  • 使用fastcgi模块提供的功能,反向代理动态内容。指令为fastcgi_pass。

  • 使用ngx_http_memcached_module模块提供的功能,反向代理memcached缓存内容,指令为memcached_pass。

  • 结合upstream模块实现更人性化的分组反向代理。

1.2 配置简单的反代实验

实验环境如下图:

未分类

反向代理服务器nginx-proxy(192.168.100.29)的配置。由于是做代理,所以配置文件的location段不再需要root、index等指令,只需几个和代理相关的指令即可。

server {
    listen       80;
    server_name  www.longshuai.com;
    location ~ .(png|jpg|jpeg|bmp|gif)$ {
        proxy_pass http://192.168.100.28:80;
    }
    location / {
        proxy_pass http://192.168.100.30:80/;
    }
    location ~ .(php|php5)$ {
        proxy_pass http://192.168.100.25:80;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

提供动态服务的nginx服务器(192.168.100.25)的配置如下。

server {
    listen       80;
    server_name  www.longshuai.com;
    location / {
        root    /www/longshuai/;
        index   index.php index.html index.htm;
    }
    location ~ .php$ {
        root /php/;
        fastcgi_pass    192.168.100.27:9000;
        fastcgi_index   test.php;
        include         fastcgi.conf;
    }
}

其中php-fpm服务器(192.168.100.27)上的/www/longshuai/index.php内容如下:

<h1>page from php-fpm</h1>
<?php
phpinfo();
?>

LB1(192.168.100.28)和LB2(192.168.100.30)的web程序都是httpd。其中作为一般静态web服务器的LB2的配置文件没有任何修改,它的/var/www/html/index.html的内容如下:

<h1>LB2:static</h1>

作为图片服务器的LB1在配置文件中添加了如下几行。且其/var/www/html/下有一个图片文件a.png。

<Files ~ ".(png|jpeg|jpg|bmp|gif)">
        Order allow,deny
        Allow from all
</Files>

经过以上的配置,可以实现如下图的功能。当访问www.longshuai.com的时候,任意以php结尾的文件请求都转发给nginx再由nginx交由php-fpm处理;任意以图片格式结尾(png/jpg/jpeg/bmp/gif)的请求都转发给LB1;任意非以上两种格式的请求都转发给LB2。

未分类

重载nginx-proxy/nginx/LB1/LB2上的nginx或者httpd。然后进行测试。

未分类

未分类

1.3 使用upstream模块实现分组反向代理

前面只使用了ngx_http_proxy_module来实现反向代理,但是其缺陷在于在nginx-proxy上定义的每条代理规则都只能转发到后台的某一台服务器上,即后端服务器无法分组。例如当图片服务器压力太大,添加一台服务器想要减轻图片服务器压力,但是仅使用proxy模块无法实现此类负载均衡到多台图片服务器上。

这时需要借助ngx_http_upstream_module模块,该模块用于定义后端服务器池,后端服务器也称为上游服务器(upstream),可以为每一种类型的后端服务器分一个组。然后在结合proxy_pass或其他代理指令将相应的请求转发到池内。

服务器池可以有多台服务器,多台服务器如何实现负载均衡和算法有关,默认是指定权重的加权均衡算法,还可以指定ip_hash算法实现同一个客户端IP发起的请求总是转发到同一台服务器上。还有一些其它算法,如最小连接数算法。最常用的还是加权算法,然后通过session共享的方式实现同一个客户端IP发起的请求转发到同一服务器上。

例如,下图描述的需求。当请求图片服务器时,可以将请求均衡到IP3和IP4两台服务器上,当请求其他静态内容,可以将请求均衡到IP5和IP6两台服务器上。

未分类

要实现这样的功能,nginx-proxy上的nginx配置文件内容大致如下:

http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;

    # define server pool
    upstream dynamic_pool {
        server IP1:80;
    }
    upstream pic_pool {
        server IP3:80 weight=2;
        server IP4:80 weight=1;
    }
    upstream static_pool {
        server IP5:80 weight=1;
        server IP6:80 weight=1;
    }

    server {
        listen 80;
        server_name www.longshuai.com;

        # define how to proxy
        location ~ .(php|php5)$ {
            proxy_pass http://dynamic_pool;
        }
        location ~ .(png|jpeg|jpg|bmp|gif)$ {
            proxy_pass http://pic_pool;
        }
        location / {
            proxy_pass http://static_pool;
        }
    }
}

1.4 ngx_http_proxy_module模块

1.4.1 指令及其意义

该模块默认安装。以下是相关指令的说明。

未分类

1.4.2 proxy_pass

proxy_pass http[s]://{ [IP:PORT/uri/] | upstream_pool };

该指令在前文示例中已经演示过了。此处只说明注意点。

当proxy_pass所在的location中使用了正则匹配时,则proxy_pass(包括fastcgi_pass和memcached_pass)定义的转发路径都不能包含任何URI信息。另外,location中使用了尾随斜线,那么proxy_pass定义的转发路径也必须使用斜线,或者都不加尾随斜线。

例如下面的配置方式是允许的。当访问www.longshuai.com/forum/时将被转发到http://192.168.100.25:8080/bbs/上。

server_name www.longshuai.com;
location /forum/ {
    proxy_pass http://192.168.100.25:8080/bbs/;
}

而如果使用了正则匹配,将是不允许的。如下。

server_name www.longshuai.com;
location ~ ^/forum/ {
    proxy_pass http://192.168.100.25:8080/bbs/;
}

只能修改转发路径使其不包含URI。如下。此时请求www.longshuai.com/forum/将转发到http://192.168.100.25:8080/forum/。

server_name www.longshuai.com;
location ~ ^/forum/ {
    proxy_pass http://192.168.100.25:8080/;
}

1.4.3 proxy_set_header

可以在nginx配置文件中的http段、server段或location段设置proxy_set_header指令。设置该指令后,传输给上游服务器的报文首部将包含相关的信息,如设置客户端的真实IP地址。设置如下:

server {
    listen       80;
    server_name  www.longshuai.com;
    location ~ .(png|jpg|jpeg|bmp|gif)$ {
        proxy_pass http://192.168.100.28:80;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
    location / {
        proxy_pass http://192.168.100.30:80/;
        proxy_set_header X-Forwarded-For $remote_addr;

    }
    location ~ .(php|php5)$ {
        proxy_pass http://192.168.100.25:80;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
}

仅在代理服务器上设置了该头部字段后还不够,因为后端服务器仅仅只是获取到它,默认并没有将其记录下来。所以需要在后端的服务的日志格式设置上记录此项或者在其他有需求的地方设置它。nginx的日志格式和apache的日志设置格式不同,以下分别是两种web程序的设置方法:

# nginx上的日志设置格式
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 logs/access.log main;

# apache上的日志设置格式
LogFormat "%{X-Forwarded-For}i %h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined

以下是nginx日志上记录的信息。

[root@xuexi nginx]# tail -1 logs/access.log 
192.168.100.29 - - [26/Apr/2017:14:35:30 +0800] "GET /index.php HTTP/1.0" 200 76990 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36" "192.168.100.1"

以下是apache日志中记录的信息。

[root@xuexi ~]# tail -1 /etc/httpd/logs/access_log
192.168.100.1 192.168.100.29 - - [26/Apr/2017:14:32:52 +0800] "GET /a.png HTTP/1.0" 200 2653 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36"

1.5 ngx_http_upstream_module模块

upstream模块定义上游服务器组。主要的指令有”upstream”、”server”、”ip_hash”。upstream指令必须定义在server段外面。

以下是一个综合示例定义方法,并非正确,只是放在一起方便比较用法。

upstream backend {
    server 192.168.100.25;
    server 192.168.100.26:80;
    server www.longshuai.com;
    server www.xiaofang.com:8080;
    server 192.168.100.27 weight=2 max_fails=2 fail_timeout=2s;
    server 192.168.100.28 down;
    server 192.168.100.29 backup;
    ip_hash;   # 定义此项后,前面的server附加项weight和backup功能失效。
}

默认使用加权均衡算法,使用ip_hash指令可设置为ip_hash算法,但使用ip_hash指令后,如果server指令中使用了weight和backup选项,这两个功能将会失效。

其中server指令后可以跟的附加选项有:

  • weight:定义该后端服务器在组中的权重,默认为1,权重越大,代理转发到此服务器次数越多。

  • max_fails和fail_timeout:定义代理服务器联系后端服务器的失败重联系次数和失败后重试等待时间。默认为1和10,如果设置为2和3,则表示只尝试联系2次,每次失败等待3秒后进行下一次重试,也就是说6秒后就能判定此后端服务器无法联系上,将负载均衡到下一台服务器上。常会配合proxy_next_upstream或者fastcgi_next_upstream或者memcached_next_upstream来指定失败时如何处理。

  • down:将此后端服务器定义为离线状态。此功能不同于直接在配置文件中删除此服务器配置或注释它。常用于ip_hash均衡算法。当使用ip_hash算法时,如果某台服务器坏了需要将其从服务器组中排除,直接从配置文件中直接删除该服务器将会导致此前分配到此后端服务器的客户端重新计算IP_HASH值,而使用down则不会。

  • backup:指定当其他非backup的server都联系不上时,将返回backup所定义的服务器内容。常用于显示sorry page。

当server指定后端服务器时使用的是主机名的方式时,需要在代理服务器上添加域名解析记录,如放到/etc/hosts中。

以下是一个配置示例。只定义了一个upstream组,所有请求都代理,权重为2比1,当192.168.100.28和192.168.100.30都断开联系时,将返回代理服务器本身配置的sorrypage。

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream web_group {
        server 192.168.100.28 weight=2 max_fails=2 fail_timeout=2s;
        server 192.168.100.30 weight=1 max_fails=2 fail_timeout=2s;
        server 127.0.0.1:80 backup;
    }
    server {
        listen 127.0.0.1:80;
        root /www/longshuai/;
        index index.html;
    }
    server {
        listen       80;
        server_name  www.longshuai.com;
        location / {
                proxy_pass http://web_group;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
                root   html;
        }
    }
}

然后在反向代理服务器上创建/www/longshuai/目录,并向目录下的index.html文件中写入”sorry….”。

mkdir -p /www/longshuai/
echo "<h1>sorry pages...</h1>" >/www/longshuai/index.html

重载代理服务器。在浏览器上输入www.longshuai.com并不断刷新,结果应该是2:1的返回权重。再依次测试停掉某一台后端服务器和两台后端都停掉的情况。

1.6 反向代理的各种情况

反向代理时,可以根据uri的后缀来代理,也可以根据uri中的目录来代理,还可以根据客户端浏览器类型来代理。例如手机访问网站时转发到某个后端服务器组,IE浏览器访问的转发到某一个后端服务器组等。

# uri后缀代理。
location ~ .(jpeg|jpg|png|bmp|gif)$ {
    proxy_pass ...
}

# 目录代理。
location ~ /forum/ {
    proxy_pass ...
}

# 浏览器类型代理。
location / {
    if ($http_user_agent ~ "MSIE") {
        proxy_pass...
    }
    if ($http_user_agent ~ "Chrome") {
        proxy_pass...
    }
}

1.7 nginx代理memcached

该模块可以从将请求代理至memcached server上,并立即从server上获取响应数据。例如:

location / {
                set $memcached_key "$uri?$args";
                memcached_pass     127.0.0.1:11211;
}

nginx代理memcached时,需要以变量$memcached_key作为key去访问memcached server上的数据。例如此处将$uri$args变量赋值给$memcached_key变量作为key去访问memcached服务器上对应的数据。

但这样的代理显然不符合真正的需求:没有实现memcached的分布式功能。当memcached server宕机时,nginx将无法从中获取任何数据。所以应该使用上游服务器组。例如:

upstream memcached {
    server 127.0.0.1:11211;
    server 127.0.0.1:11212;
    server 127.0.0.1:11213;
    server 127.0.0.1:11214;
}

server {
    listen       80;
    server_name  dev.hwtrip.com;

    location ^~ /cache/ {
        set            $memcached_key "$uri$args";
        memcached_pass memcached;

但这也不适合,因为memcached是基于一致性哈希算法的,而upstream模块默认并不支持一致性哈希算法。可以通过upstream模块的hash指令或者另外使用一个第三方模块ngx_http_upstream_consistent_hash。

如果使用的是upstream模块的hash指令,配置如下:

upstream memcached {
    hash "$uri$args" consistent;
    server 127.0.0.1:11211;
    server 127.0.0.1:11212;
    server 127.0.0.1:11213;
    server 127.0.0.1:11214;
}

这样,各上游主机就通过hash一致性的算法进行负载均衡。

如果使用的是第三方模块ngx_http_upstream_consistent_hash,则在模块添加成功后如下配置upstream组:

upstream memcached {
    consistent_hash consistent;
    server 127.0.0.1:11211;
    server 127.0.0.1:11212;
    server 127.0.0.1:11213;
    server 127.0.0.1:11214;
}

二、nginx自带的缓存功能

nginx的ngx_http_proxy_module自带了缓存功能。有几种缓存:网页内容缓存,日志缓存,打开文件缓存,fastcgi缓存。fastcgi缓存功能应慎用,因为动态程序的前后逻辑可能改变了,缓存后的结果可能并非实际所需结果。

在说明nginx自带的缓存功能之前,需说明其缺陷。nginx的缓存功能主要用于缓存体积较小的页面资源,当数据较大时很容易出现瓶颈。在页面资源的缓存功能上,它属于业余玩家。而squid是科班出身,功能最全面,可以缓存大量数据,但架构太老,性能一般。varnish则是此类缓存的新贵,架构较新,内存管理完全交由操作系统内核,性能是squid的几倍之强,但缓存的内容不足squid。

本节所讲的主要是nginx自带缓存的网页内容缓存。当实现网页内容缓存时,作为web服务程序,它可以缓存自身返回给客户端的数据,包括读取的图片、文件等;作为代理,它可以缓存来自后端的数据。缓存后的数据在内存中有,也会放在设定的目录下。这样以后客户端继续请求相同资源时,可以直接从内存中或者自身的磁盘中获取并返回给客户端。当缓存超出指定的空间大小时,将会有一个专门的线程cache_manager来清理缓存。

定义的相关指令主要有3个:proxy_cache_path、proxy_cache、proxy_cache_valid。

  • proxy_cache_path:它的语法比较复杂,但用起来很简单。
proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];

其中proxy_cache_path path [levels=levels] keys_zone=name:size [max_size=size]这几项是一般使用的选项和必需项。以下为一示例。

proxy_cache_path /usr/local/nginx/cache_dir levels=1:2 keys_zone=cache_one:20m max_size=1g;

其中:

  • path:定义缓存放在磁盘的哪个目录下。此处表示定义在/usr/local/nginx/cache_dir目录下。目录不存在会自动创建。

  • levels:定义缓存目录的级别,同时定义缓存目录名称的字符数。例如levels=1:2:2表示3级目录,且第一级目录名1个字符,第二级目录2个字符,第三级目录2个字符。目录最多3级,目录名最多为2个字符。例如上例中”levels=1:2″产生的缓存文件路径可能是这样的”/usr/local/nginx/cache_dir/d/f1/50a3269acaa7774c02d4da0968124f1d”,注意其中加粗的字体。

  • keys_zone:定义缓存标识名称和内存中缓存的最大空间。name部分必须唯一,在后面会引用name来表示使用该缓存方法。

  • max_size:定义磁盘中缓存目录的最大空间。即path定义的文件最大空间。

该指令定义后只是定义了一种缓存方法,并非开启了缓存。

  • proxy_cache:定义要使用哪个缓存方法。使用proxy_cache_path中的name来引用。

例如引用上例定义的cache_one。

proxy_cache cache_cache;
  • proxy_cache_valid:根据状态码来指定缓存有效期。

例如,下面的表示状态码为200和302的状态缓存1小时,状态码为404时即page not found的缓存只有1分钟,防止客户端请求一直错误,状态码为其他的则缓存5分钟。

proxy_cache_valid 200 302 1h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 5m;

如果不指定状态码,只指定时间,则默认只缓存状态码200、301、302各5分钟,其他的状态码不缓存。

以下是代理服务器192.168.100.29上定义的缓存示例。

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

        upstream web_group {
                server 192.168.100.28 weight=2 max_fails=2 fail_timeout=2s;
                server 192.168.100.30 weight=1 max_fails=2 fail_timeout=2s;
                server 127.0.0.1:80 backup;
        }
        proxy_cache_path /usr/local/nginx/cache_dir levels=1:2 keys_zone=cache_one:20m max_size=1g;
        server {
                listen 127.0.0.1:80;
                root /www/longshuai/;
                index index.html;
        }
        server {
                listen       80;
                server_name  www.longshuai.com;
              # 在响应报文中添加缓存首部字段
                add_header X-Cache "$upstream_cache_status from $server_addr";
                location / {
                        proxy_pass http://web_group;
                        proxy_cache cache_one;
                        proxy_cache_valid 200 1h;
                        proxy_cache_valid 404 1m;
                        proxy_cache_valid any 5m;
                }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

其中添加的一行”add_header X-Cache “$upstream_cache_status from $server_addr”;”表示在响应报文的头部加上一字段X-Cache,其值为是否命中缓存的状态($upstream_cache_status),从哪台服务器上($server_addr)取得的缓存。 重载代理服务器的配置文件后,在客户端打开”开发者工具”进行测试。

未分类

由于是第一次提供缓存功能,所以结果是未命中缓存。此时已经将缓存保存下来了。 再进行测试,结果将命中缓存是”hit from 192.168.100.29″。

未分类

查看缓存目录。

[root@xuexi nginx]# tree /usr/local/nginx/cache_dir/  
/usr/local/nginx/cache_dir/
├── 3
│   └── 26
│       └── 3abcc5796b407cf3db2716539d256263
└── d
    └── f1
        └── 3b37290aabefe7369a4680875f763f1d

如果想要删除缓存,只需删除对应的目录即可。

CentOS7服务器连接nas拷贝文件

1. 给nas配置固定ip并用网线直接连接到nas上

先把nas连接到局域网里,在局域网里用windows下的nas厂商提供的工具查找到了nas的ip,进去web页面将ip设置为固定ip 192.168.3.3。 CentOS服务器有两个网卡,em1正在使用(dhcp分配的ip)不可变动,em2没在使用。

用网线将em2和nas的网口直连。配置em2网卡的IP为192.168.3.5。配置centos路由,先查看route。

[root@localhost ~]# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.31.0.1      0.0.0.0         UG    100    0        0 em1
172.31.0.0      0.0.0.0         255.255.255.0   U     100    0        0 em1
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

如果发现有em2的route,先route del -net x.x.x.x netmask x.x.x.x dev em2 删掉。
添加到192.168.3.3的route。

route add -host 192.168.3.3 dev em2
[root@localhost ~]# route        
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.31.0.1      0.0.0.0         UG    100    0        0 em1
172.31.0.0      0.0.0.0         255.255.255.0   U     100    0        0 em1
192.168.3.3     0.0.0.0         255.255.255.255 UH    0      0        0 em2
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

这样再ping 192.168.3.3就可以ping通了。

2. 安装SmbClient,把nas的文件夹mount到/mnt/smb下。

yum install samba samba-client samba-swat
mkdir /mnt/smb
smbclient -L 198.168.3.3 -U username%password  #列出该IP地址所提供的共享文件夹
mount -o username=username,password=123456 //192.168.3.3/tmp /mnt/smb/ #mount

这样就可以到/mnt/smb访问nas了。

部署LAMP+NFS实现双Web服务器负载均衡

未分类

一、需求分析

  1. 前端需支持更大的访问量,单台Web服务器已无法满足需求了,则需扩容Web服务器;

  2. 虽然动态内容可交由后端的PHP服务器执行,但静态页面还需要Web服务器自己解析,那是否意味着多台Web服务器都需要在各自的系统中都存有一份静态页面数据呢?那么如果能将静态页面集中存放,所有Web服务器都来集中地取文件,对于文件的一致性就有了保障,这个集中地就叫做“文件共享服务器”;

二、需求实现

  1. web1充当http服务器和DNS解析服务器,客户端到web1和web2的请求,如果是静态资源请求通过php主机的NFS服务挂载的存储返回结果

  2. web1和web2对于客户端动态资源请求都反向代理到后端php服务器进行执行后返回结果

  3. web1和web2实现DNS轮询,客户端访问博客网站是负载均衡的。

  4. 建立wordpress博客

  5. 数据库存储wordpress博客的各种数据

三、架构图

未分类

四、步骤概述

  1. 部署LAMP环境、配置NFS服务器

  2. web1、web2、php服务器全部挂载NFS共享目录为网站根目录

  3. 配置httpd实现动静分离

  4. 配置DNS实现负载均衡

五、详细过程

1. web1、web2服务器编译安装Apache

# 安装依赖包
yum groupinstall "development tools"
yum install openssl-devel expat-devel pcre-devel 
#
# 解压文件
tar xvf apr-1.6.2.tar.gz 
tar xvf apr-util-1.6.0.tar.gz 
tar xvf httpd-2.4.27.tar.bz2 
cp -r apr-1.6.2 httpd-2.4.27/srclib/apr
cp -r apr-util-1.6.0 httpd-2.4.27/srclib/apr-util
#
# 编译安装
cd httpd-2.4.27/
./configure 
--prefix=/app/httpd24 
--sysconfdir=/etc/httpd24 
--enable-so --enable-ssl 
--enable-rewrite --with-zlib 
--with-pcre --with-included-apr 
--enable-modules=most 
--enable-mpms-shared=all 
--with-mpm=prefork
#
make && make install
#
#配置环境变量
vim /etc/profile.d/lamp.sh
    PATH=/app/httpd24/bin/:$PATH
. /etc/profile.d/lamp.sh
#
# 启动服务
apachectl start

2. 数据库服务器二进制安装mariadb

# 解压文件
tar xvf mariadb-10.2.8-linux-x86_64.tar.gz  -C /usr/local/
cd /usr/local
#
# 创建软连接,mariadb在/usr/local下必须名为mysql,可以创建软连接,可以改名
ln -s mariadb-10.2.8-linux-x86_64/ mysql
#
# 创建用户
useradd -r -m -d /app/mysqldb -s /sbin/nologin mysql 
cd mysql/
#
# 初始化数据库
scripts/mysql_install_db --datadir=/app/mysqldb --user=mysql
#
# 创建配置文件
mkdir /etc/mysql
cp support-files/my-large.cnf   /etc/mysql/my.cnf
#
# 修改配置文件,指定数据库存放路径
vim /etc/mysql/my.cnf
[mysqld]
datadir = /app/mysqldb             在mysqld下添加这三行
innodb_file_per_table = ON
skip_name_resolve = ON
#
# 复制启动脚本,添加开机自动启动
cp support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld
chkconfig --list 
service mysqld start
#
# 创建日志目录
mkdir /var/log/mariadb
chown mysql /var/log/mariadb/
#
#添加环境变量
vim /etc/profile.d/lamp.sh 
   PATH=/app/httpd24/bin/:/usr/local/mysql/bin/:$PATH
. /etc/profile.d/lamp.sh
#
#调用安全加固脚本,加固数据库。汉字为每一项的翻译
mysql_secure_installation
  是否设置root密码
  输入密码
  确认密码
  是否设置匿名用户
  是否允许root远程登录
  删除test数据库
  现在是否生效

3. PHP应用服务器编译安装PHP7

# 安装依赖包
yum install libxml2-devel bzip2-devel libmcrypt-devel gcc openssl-devel
tar xvf  php-7.1.7.tar.bz2
#
#编译安装
cd php-7.1.7.tar.bz2
./configure 
--prefix=/app/php 
--enable-mysqlnd                           #mysqlnd 指明Mysql不再本地
--with-mysqli=mysqlnd 
--with-pdo-mysql=mysqlnd 
--with-openssl 
--enable-mbstring 
--with-freetype-dir  
--with-jpeg-dir 
--with-png-dir 
--with-zlib 
--with-libxml-dir=/usr 
--enable-xml 
--enable-sockets 
--enable-fpm                               #用FPM模式
--with-mcrypt 
--with-config-file-path=/etc/php 
--with-config-file-scan-dir=/etc/php.d 
--with-bz2
#
# 创建PHP配置文件
mkdir /etc/php/
cp php.ini-production /etc/php/php.ini
#
# 复制服务脚本,添加开机自动启动
cp   sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
chmod +x /etc/init.d/php-fpm
chkconfig --add php-fpm
chkconfig --list  php-fpm
#
# 创建fpm的配置文件
cd /app/php/etc
cp php-fpm.conf.default php-fpm.conf
cd /app/php/etc/php-fpm.d/
cp www.conf.default www.conf
vim www.conf
    listen = 172.18.68.23:9000              #设置监听的IP,注释监听所有, 只写端口监听鄋
    ;listen.allowed_clients = 127.0.0.1.    #把这项注释掉,分号为注释
systemctl start php-fpm

4. 配置NFS服务器

NFS服务器的配置特别简单,最重要的时配置完后就赶紧将NFS共享目录挂载至web1、web2、PHP服务器的网站根目录。

mkdir -pv /app/nfs/web #创建共享目录,此目录为网站的根目录,实现统一管理。

vim /etc/exports
  /app/nfs/web 172.18.0.0/16(ro,sync,root_squash,no_all_squash)
# 允许172.18.0.1网段挂载NFS共享,如果要提高安全性应该控制到主机
  • Web1服务器

mount 172.18.68.24:/app/nfs/web /app/httpd24/htdocs #/app/httpd24/htdocs为httpd.conf中的根目录

  • Web2服务器

mount 172.18.68.24:/app/nfs/web /app/httpd24/htdocs #/app/httpd24/htdocs为httpd.conf中的根目录

  • PHP应用服务器

mkdir /app/httpd24/htdocs #PHP没有根目录,/app/httpd24/htdocs为NFS的挂载点。
mount 172.18.68.24:/app/nfs/web /app/httpd24/htdocs

5. 配置Apache实现动静分离

  • 加载模块
vim /etc/httpd24/httpd.conf
    LoadModule proxy_module modules/mod_proxy.so                       #取消两行的注释,加载两模块
    LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
  • 动静分离

在配置文件的末尾追加这四行,利用代理将所有以.php结尾的文件交给PHP服务器处理,实现动静分离

vim /etc/httpd24/httpd.conf
  AddType application/x-httpd-php .php
  AddType application/x-httpd-php-source .phps
  ProxyRequests Off 关闭正向代理
  ProxyPassMatch  ^/(.*.php)$ fcgi://127.0.0.1:9000/app/httpd24/htdocs/$1  
#要确保PHP服务器中有这个目录,(在NFS中创建这个目录,且将NFS挂载至此目录。)
apachectl restart

6. 部署wordpress博客

因为web1、web2、PHP服务器都使用NFS共享的目录作为根目录,所以只需要将wordpress博客系统部署在NFS服务器上即可让所有服务器得到同样的数据。

  • 安装博客程序
# 解压博客程序
tar xvf wordpress-4.8.1-zh_CN.tar.gz  -C /app/httpd24/htdocs
cd /app/httpd24/htdocs
mv wordpress/ blog/
# 创建配置文件
cd /app/httpd24/htdocs/blog/
cp wp-config-sample.php  wp-config.php
  • 配置数据库

wordpress需要数据库,所以在此先创建一个wordpress专用的数据库,且创建授权用户。

mysql -uroot -pCentOS
create datebase wpdb;
grant all on wpdb.* to wpuser@'172.18.68.%' identified by 'centos';
  • 配置wordpress连接数据库
# 编辑配置文件,写入创建的IP、数据库、与用户性
vim wp-config.php
define('DB_NAME', 'wpdb');
#
/** MySQL数据库用户名 */
define('DB_USER', 'wpuser');
#
/** MySQL数据库密码 */
define('DB_PASSWORD', 'centos');
#
/** MySQL主机 */
define('DB_HOST', 'localhost');

7. 登录测试

  • 浏览器打开,http://IP,设置管理员的用户名密码,点击安装

未分类

  • 输入用户名密码,即可进入博客网站的后台页面。

未分类

  • 默认风格的博客页面首页,还是比较好看滴

未分类

8. 配置DNS负载均衡

购买了单独域名后,在后台控制面板中添加两条A记录,就可以达到负载均衡。

到这里基于LAMP+NFS架构的双Web服务器、动静分离网站就搭建完成了。
双WEB服务器架构的好处在于如果有一台服务器宕机不会是整个网站瘫痪。

NFS共享存储的好处在于,DNS负载均衡后,不论用户被分配到哪台主机上,都能看到相同的页面得到相同的结果。

Rhel7下NFS的配置以及使用

一、NFS概述

1. NFS概述

NFS 是Network File System的缩写,即网络文件系统。

一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向外公布。

功能是通过网络让不同的机器、不同的操作系统能够彼此分享个别的数据,让应用程序在客户端通过网络访问位于服务器磁盘中的数据,是在类Unix系统间实现磁盘文件共享的一种方法。

NFS 的基本原则是”容许不同的客户端及服务端通过一组RPC分享相同的文件系统”,它是独立于操作系统,容许不同硬件及操作系统的系统共同进行文件的分享。

NFS在文件传送或信息传送过程中依赖于RPC协议。

RPC,远程过程调用 (Remote Procedure Call) 是能使客户端执行其他系统中程序的一种机制。

NFS本身是没有提供信息传输的协议和功能的,但NFS却能让我们通过网络进行资料的分享,这是因为NFS使用了一些其它的传输协议。而这些传输协议用到这个RPC功能的。可以说NFS本身就是使用RPC的一个程序。或者说NFS也是一个RPC SERVER。所以只要用到NFS的地方都要启动RPC服务,不论是NFS SERVER或者NFS CLIENT。这样SERVER和CLIENT才能通过RPC来实现PROGRAM PORT的对应。可以这么理解RPC和NFS的关系:NFS是一个文件系统,而RPC是负责负责信息的传输。

2. NFS的一些守护进程

NFS系统守护进程

nfsd:它是基本的NFS守护进程,主要功能是管理客户端是否能够登录服务器;

mountd:它是RPC安装守护进程,主要功能是管理NFS的文件系统。

当客户端顺利通过nfsd登录NFS服务器后,在使用NFS服务所提供的文件前,还必须通过文件使用权限的验证。它会读取NFS的配置文件/etc/exports来对比客户端权限。

rpcbind:主要功能是进行端口映射工作。

当客户端尝试连接并使用RPC服务器提供的服务(如NFS服务)时,rpcbind会将所管理的与服务对应的端口提供给客户端,从而使客户可以通过该端口向服务器请求服务。

二、测试机概述

server端:

  • 主机名:nfsserver
  • ip:192.168.0.110

client端:

  • 主机名:fundation10
  • ip:192.168.0.199

Operating System均为: Red Hat Enterprise Linux Server 7.0 (Maipo)

三、server端NFS服务的搭建

以下操作在server端:

1. 安装NFS服务

  • nfs-utils :包括基本的NFS命令与监控程序
  • rpcbind :支持安全NFS RPC服务的连接

所以需要安装rpcbind和nfs-utils两个包

yum install rpcbind nfs-utils -y

2. NFS服务器的配置

1)查看NFS服务的配置文件

rpm -qc nfs-utils

看到的内容是这些

/etc/nfsmount.conf 
/etc/request-key.d/id_resolver.conf 
/etc/sysconfig/nfs 
/var/lib/nfs/etab 
/var/lib/nfs/rmtab 
/var/lib/nfs/state 
/var/lib/nfs/xtab

但是/etc/exports才是nfs服务的主配置文件

这个文件是NFS的主要配置文件,不过系统并没有默认值,所以这个文件不一定会存在,可能要使用vim手动建立,然后在文件里面写入配置内容。

2)了解server端NFS服务主配置文件的输出目录以及输出属性
首先我们来看一下/etc/exports的格式

<输出目录> [客户端1选项(访问权限,用户映射,其他)] [客户端2选项(访问权限,用户映射,其他)]

其次,详细了解

##############输出目录:###################

输出目录是指NFS系统中需要共享给客户机使用的目录;

##############客户端:####################

客户端是指网络中可以访问这个NFS输出目录的计算机

#############客户端常用的指定方式###########

    指定ip地址的主机:192.168.0.200

    指定子网中的所有主机:192.168.0.0/24 192.168.0.0/255.255.255.0
    指定域名的主机:nfs.cnhzz.com
    指定域中的所有主机:*.cnhzz.com
    所有主机:*

##################选项:####################

选项用来设置输出目录的访问权限、用户映射等。

NFS主要有3类选项:
1)访问权限选项
    设置输出目录只读:ro
    设置输出目录读写:rw
2)用户映射选项
    all_squash:将远程访问的所有普通用户及所属组都映射为匿名用户或用户组(nfsnobody);
    no_all_squash:与all_squash取反(默认设置);
    root_squash:将root用户及所属组都映射为匿名用户或用户组(默认设置);
    no_root_squash:与rootsquash取反;
    anonuid=xxx:将远程访问的所有用户都映射为匿名用户,并指定该用户为本地用户(UID=xxx);
    anongid=xxx:将远程访问的所有用户组都映射为匿名用户组账户,并指定该匿名用户组账户为本地用户组账户(GID=xxx);
3)其它选项
    secure:限制客户端只能从小于1024的tcp/ip端口连接nfs服务器(默认设置);
    insecure:允许客户端从大于1024的tcp/ip端口连接服务器;
    sync:将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性;
    async:将数据先保存在内存缓冲区中,必要时才写入磁盘;
    wdelay:检查是否有相关的写操作,如果有则将这些写操作一起执行,这样可以提高效率(默认设置);
    no_wdelay:若有写操作则立即执行,应与sync配合使用;
    subtree_check:若输出目录是一个子目录,则nfs服务器将检查其父目录的权限(默认设置);
    no_subtree_check:即使输出目录是一个子目录,nfs服务器也不检查其父目录的权限,这样可以提高效率;

3. 正式配置NFS服务的主配置文件

要求:

1.将/testdata作为输出目录(共享目录),
2.只共享给192.168.0网段的主机
3.客户端对该目录可读可写
4.数据要求同步
5.若输出目录是一个子目录,则nfs服务器将检查其父目录的权限(默认设置);

步骤:

1)建立/testdata

mkdir /testdata

2)写入配置文件

那么就要在server端写入以下:

/testdata 192.168.0.0/24(rw,sync,subtree_check)

!!!注意*和()之间没有空格

4. 开启服务rpcbind,nfs-utils

systemctl start rpcbind nfs

一定先启动rpcbind

5. 查看共享目录

用命令showmount或者exportfs

showmount -e 192.168.0.110
exportfs

未分类

6. 要求server端防火墙通过NFS服务

firewall-cmd --permanent --add-service=nfs
systemctl restart firewalld.service

或者直接关闭防火墙

四、client挂载NFS服务器共享的目录

1. 将NFS服务器共享的目录挂载至client本机的/mnt下

mount 192.168.0.110:/testdata /mnt

2. 尝试ls/touch,了解server端给自己打开了哪些权限
我以client端普通用户root挂载,普通用户没有挂载权限,得到以下结果

未分类

然后查看server端给我client端的权限,果然缺少wx权限

未分类

那么在server端给client端这样的权限,

未分类

再次尝试:

未分类

仍然无法touch,原因何在

未分类

no_root_squash 是让root保持权限,root_squash是将root映射成nobody,而服务器端并没有设置no_root_squash权限

那么我们设置no_root_squash 映射属性吧

未分类

这样就OK了,下面一项就是对它的解释

五、server端开放某些权限,以供client端使用

关于权限的分析

1、客户端连接时候,对普通用户的检查
如果明确设定了普通用户被压缩的身份,那么此时客户端用户的身份转换为指定用户;

如果NFS server上面有同名用户,那么此时客户端登录账户的身份转换为NFS server上面的同名用户;

如果没有明确指定,也没有同名用户,那么此时 用户身份被压缩成nfsnobody;

2、客户端连接的时候,对root的检查

如果设置no_root_squash,那么此时root用户的身份被压缩为NFS server上面的root;

如果设置了all_squash、anonuid、anongid,此时root 身份被压缩为指定用户;

如果没有明确指定,此时root用户被压缩为nfsnobody;

如果同时指定no_root_squash与all_squash 用户将被压缩为 nfsnobody,如果设置了anonuid、anongid将被压缩到所指定的用户与组;

六、客户端取消挂载

使用umount mountpoint

umount /mnt/

七、相关命令介绍

1、exportfs

如果我们在启动了NFS之后又修改了/etc/exports,是不是还要重新启动nfs呢?这个时候我们就可以用exportfs 命令来使改动立刻生效,该命令格式如下:

# exportfs [-aruv]
-a    # 全部挂载或卸载 /etc/exports中的内容
-r     #重新读取/etc/exports 中的信息 ,并同步更新/etc/exports、/var/lib/nfs/xtab
-u  #卸载单一目录(和-a一起使用为卸载所有/etc/exports文件中的目录)
-v     #在export的时候,将详细的信息输出到屏幕上。

具体例子:

[root@server ~]# exportfs -au #卸载所有共享目录

2、nfsstat

查看NFS的运行状态,对于调整NFS的运行有很大帮助。

3、rpcinfo

查看rpc执行信息,可以用于检测rpc运行情况的工具
rpcinfo -p看出RPC开启的端口所提供的程序有哪些。

4、showmount

-a 显示已经于客户端连接上的目录信息
-e IP或者hostname 显示此IP地址分享出来的目录
最后注意两点,虽然通过权限设置可以让普通用户访问,但是挂载的时候默认情况下只有root可以去挂载,普通用户可以执行sudo。

NFS server 关机的时候一点要确保NFS服务关闭,没有客户端处于连接状态!通过showmount -a 可以查看,如果有的话用kill killall pkill 来结束,(-9 强制结束)

八、处理showmount报错

如果使用showmount报错

类似clnt_create: RPC: Program not registered

解决方式

server端重启nfs,client端重新挂载,给server和client分别在/etc/hosts加上解析

server

192.168.0.110 nfsserver

client

192.168.0.199 fundation10

NFS网络文件系统

说明:以下配置都是以root用户角色执行的,并且基于RHEL7设置的,参考书籍《Linux就该这么学》。

什么是NFS?

NFS就是Network FileSystem的缩写,是由Sun公司发展出来的。其目的是让linux 机器之间彼此分享文档。NFS可以让服务器端共享的目录挂载到本地客户机上,对于本地客户机器来说,远程服务器上的目录就好像自己的一部分。NFS文件系统协议允许网络中的主机通过TCP/IP协议进行资源共享,能够让Linux客户端像使用本地资源一样读写远端NFS服务端的文件内容。

NFS有哪些作用?

它的功能是把NFS服务器(即Linux主机)的某个目录挂载到开发板的文件系统上。这样,开发板就可以执行该目录中的可执行程序。这样做的优点在于:不用将程序写入开发板的Flash,减少了对Flash的损害,同时也方便调试。

在嵌入式系统开发中主要用于NFS网络根文件系统启动或者网络加载调试应用程序。

NFS允许系统将其目录和文件共享给网络上的其他系统。通过NFS,用户和应用程序可以访问远程系统上的文件,就像它们是本地文件一样。那么NFS最值得注意的优点有:

(1)本地工作站可以使用更少的磁盘空间,因为常用数据可以被保存在一台机器上,并让网络上的其他机器可以访问它。

(2)不需要为用户在每台网络机器上放一个用户目录,因为用户目录可以在NFS服务器上设置并使其在整个网络上可用。

(3)存储设备如软盘、光驱及USB设备可以被网络上其它机器使用,这可能可以减少网络上移动设备的数量。

NFS运行机制:

NFS是通过网络进行数据传输,并且传输数据时使用的端口是随机的,但是唯一的限制就是端口小于1024。客户端怎么知道服务器使用的是哪个端口,此时就要用到远程过程调用RPC。

其实,NFS运行在SUN的RPC(Remote Procedure
Call,远程过程调用)基础上,RPC定义了一种与系统无关的方法来实现进程间通信,由此,NFS Server也可以看作是RPC
Server。正因为NFS是一个RPC服务程序,所以在使用它之前,先要映射好端口——通过portmap设定。比如:某个NFSClient发起NFS服务请求时,它需要先得到一个端口(port),所以它先通过portmap得到portnumber(不仅是NFS,所有的RPC服务程序启动之前,都需要先设定好portmap)。

注意:在启动RPC服务(比如NFS)之前,需要先启动portmap服务。

NFS具体配置步骤:

一、服务端配置

1、安装NFS服务

yum install nfs-utils

2、在NFS服务端主机上面建立用于NFS文件共享的目录,设置较大的权限来保证其他人也一样有写入的权限:

mkdir /nfsfile
chmod -Rf 777 /nfsfile
echo "This is a test file" > /nfsfile/readme

3、NFS服务程序的配置文件为/etc/exports,默认里面是空白没有内容的,可以按照共享目录的路径 允许访问的NFS资源客户端(共享权限参数)的格式来写入参数,定义要共享的目录与相应的权限。共享权限参数如下:

未分类

例如想要把/nfsfile目录共享给所有属于192.168.10.0/24这个网段的用户主机,并且让这些用户拥有读写权限,自动同步内存数据到本地硬盘,以及把对方root超级用户映射为本地的匿名用户等等特殊权限参数,那么就可以按照下面的格式来写入配置文件:

vim /etc/exports
/nfsfile 192.168.10.*(rw,sync,root_squash)

4、启动运行NFS共享服务程序,由于NFS服务在文件共享过程中是依赖RPC服务进行工作了,RPC服务用于把服务器地址和服务端口号等信息通知给客户端,因此要使用NFS共享服务的话,顺手也要把rpcbind服务程序启动,并且把这两个服务一起加入到开机启动项中:

systemctl restart rpcbind
systemctl enable rpcbind
systemctl start nfs-server
systemctl enable nfs-server

二、客户端配置

1、首先用showmount命令查询NFS服务端的远程共享信息,输出格式为“共享的目录名称 允许使用客户端地址”:

常用参数如下:

未分类

showmount -e 192.168.10.10  # 显示远程服务端共享的信息

2、然后在客户端系统上面创建一个挂载目录,使用mount命令的 -t 参数指定挂载文件系统的类型,以及后面写上服务端的IP地址,共享出去的目录以及挂载到系统本地的目录。

mkdir /nfsfile         # 创建本地用来挂载的文件夹
mount -t nfs 192.168.10.10:/nfsfile /nfsfile  # 挂载

3、最后挂载成功后,切换到本地目录就应该能够顺利查看到在服务端写入的文件内容了,如果希望远程NFS文件共享能一直有效,还可以写入到fstab文件中:

cat /nfsfile/readme  # 可以在本地目录查看到之前在服务端写入的文件内容
vim /etc/fstab       # 编辑fstab文件保证开机启动仍然有效
    192.168.10.10:/nfsfile /nfsfile nfs defaults 0 0    #具体写入的内容

MySQL跨表更新 多表update sql语句总结

MySQL跨表更新一直是大家所关心的话题,本文介绍mysql多表 update在实践中几种不同的写法,需要的朋友可以参考下。

假定我们有两张表,一张表为Product表存放产品信息,其中有产品价格列Price;另外一张表是ProductPrice表,我们要将ProductPrice表中的价格字段Price更新为Price表中价格字段的80%。

在MySQL中我们有几种手段可以做到这一点,一种是update table1 t1, table2 ts …的方式:

UPDATE product p, productPrice pp SET pp.price = pp.price * 0.8
WHERE p.productId = pp.productId AND p.dateCreated < '2004-01-01' 

另外一种方法是使用inner join然后更新:

UPDATE product p INNER JOIN productPrice pp ON p.productId = pp.productId
SET pp.price = pp.price * 0.8 WHERE p.dateCreated < '2004-01-01'

另外我们也可以使用left join来做多表update,比方说如果ProductPrice表中没有产品价格记录的话,将Product表的isDeleted字段置为1,如下sql语句:

UPDATE product p LEFT JOIN productPrice pp ON p.productId = pp.productId
SET p.deleted = 1 WHERE pp.productId IS null 

另外,上面的几个例子都是两张表之间做关联,但是只更新一张表中的记录,其实是可以同时更新两张表的,如下sql:

UPDATE product p INNER JOIN productPrice pp ON p.productId = pp.productId
SET pp.price = pp.price * 0.8, p.dateUpdate = CURDATE() WHERE p.dateCreated < '2004-01-01' 

两张表做关联,更新了ProductPrice表的price字段和Product表字段的dateUpdate两个字段。

一次由MySQL跨库操作所引发的主从复制中断

今天,所有MySQL从服务器上的主从复制都被异常中断了,登陆到其中一台上执行show slave statusG,发现如下错误:

Last_Error: Error 'Operation DROP USER failed for 'guest'@'localhost'' on query. Default database: 'work'. Query: 'drop user 'guest'@'localhost''

也就是说,是 drop user ‘guest’@’localhost’ 这条命令导致的,而这样的操作我们通常都只会在Master上进行,并且该操作应该只会影响到“mysql”这个系统数据库。之前这种操作进行了很多次,可为什么唯独这一次会出问题呢?

经过一番调查之后,最终找到了问题的根源,那就是,
“binlog-do-db, binlog-ignore-db, replicate-do-db, replicate-ignore-db” 这一类参数,并非想象中可靠!

通常,我们会以为只要设定了以上参数,MySQL的主从复制就会只对我们设定的数据库生效。但事实上,MySQL不是根据内容来判断的,而是很傻瓜的根据你执行了“use work”或在初始连接时指定的数据库来判断的。
而这次,我们在执行drop user之前,因为需要从“work”数据库select一些数据,就use work进入到了work数据库,而大家都知道在执行drop user的时候是不需要进入“mysql”这个系统数据库的,所以就直接执行了drop user,但因为MySQL的判断我们是在use work之后执行的,所以认为是针对“work”数据库的操作就同步了下去,而从服务上都是没有guest@localhost这样的用户的,所以就造成了错误,导致主从复制的中断。

因此,在有主从复制架构的MySQL服务器环境中,我们要尽量避免这样的跨库操作,确保是在执行了正确的use dbname之后再执行命令。

这类故障的恢复方案很简单,就是跳过这一条SQL。

stop slave;
set global sql_slave_skip_counter=1;
start slave;
show slave statusG

参考资料:
http://www.mysqlperformanceblog.com/2009/05/14/why-mysqls-binlog-do-db-option-is-dangerous/

通过MYSQL的二进制日志找回误删记录

同事在开发时,使用正式数据库测试功能,不小心误删了数据库中的一条数据。幸好数据库有开启Binlog(为了做主从复制),Binlog记录了数据库执行的每条SQL语句,抱着死马当活马医的心态,利用Binlog看能不能找回误删的数据。

数据大概是在14:20左右删除的,首先利用mysqlbinlog命令导出那段时间的日志,执行下面的命令:

mysqlbinlog --start-datetime="2017-10-13 14:15:00"  --stop-datetime="2017-10-13 14:25:00"  mysql_bin.xxxxxx > data.sql

将14:15至14:25的日志记录导出到data.sql文件中,打开data.sql文件,查找定位到被删除数据的表:

未分类

如上图就是一条SQL语句的执行记录,其中黄色字体部分就是实际执行的SQL语句,语句经过BASE64编码,可以使用-v参数,让mysqlbinlog将执行的语句通过注释的方式显示出来,再使用-base64-output=decode-rows参数让mysqlbinlog把看不懂的BASE64编码隐藏起来,最后执行的命令变成这样:

mysqlbinlog --base64-output=decode-rows -v --start-datetime="2017-10-13 14:15:00"  --stop-datetime="2017-10-13 14:25:00"  mysql_bin.xxxxxx > data.sql

打开data.sql文件,查找定位到被删除数据的表:

未分类

可以看到执行的删除语句了,而且日志还帮我们把被删除记录的每个字段值都记录下来了,只要复制这些字段的值,就可以恢复被删除的记录了!