tomcat简单优化

一、内存优化

1、修改tomcat路径bin目录下的catalina.sh

cat >> catalina.sh << END
JAVA_OPTS='-Xms20480m -Xmx20480m -Xss256k -XX:PermSize=256M -XX:MaxNewSize=256m -XX:MaxPermSize=256m'
END

参数:

-Xms  jvm初始化堆内存大小
-Xmx  jvm堆的最大内存   #堆内存建议设为服务器内存的60%~80%
-Xss  线程栈大小       #一般设置为256k

-XX:PermSize     jvm非堆区初始内存分配大小
-XX:MaxPermSize  jvm非堆区最大内存 #非堆内存不可回收,看项目大小而定

2、重启tomcat验证:jmap -heap 12345(tomcat PID)

二、配置优化

修改server.xml添加参数

maxThreads        客户请求最大线程数 
minSpareThreads   初始化时创建的 socket 线程数 
maxSpareThreads   连接器的最大空闲 socket 线程数 
enableLookups     若设为true, 则支持域名解析,可把 ip 地址解析为主机名 
redirectPort      在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口 
acceptAccount     监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads) 
connectionTimeout 连接超时 
minProcessors     服务器创建时的最小处理线程数 
maxProcessors     服务器同时最大处理线程数 
URIEncoding URL   统一编码

生产中配置:

<Connector executor="tomcatThreadPool"
           port="8080"
           protocol="HTTP/1.1"
           connectionTimeout="20000"
           minSpareThreads="150" 
           maxSpareThreads="500"
           enableLookups="false" 
           disableUploadTimeout="true" 
           acceptCount="1000"   
           maxThreads="1000" 
           maxProcessors="1000" 
           minProcessors="5"
           useURIValidationHack="false"
           compression="on" 
           compressionMinSize="2048"
           compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
           uriencoding="utf-8"
           redirectPort="8443" />

三、优化网卡驱动

$ cat >> /etc/sysctl.cnf << END
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768 
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 65536

END

$ sysctl -p

tcpdump只抓取HTTP报文头部

因为要做一个需求,我需要调研现网请求http头部的大小,都有什么字段,shell脚本代码如下所示

#! /bin/bash

s_512=0
s_512_1k=0
s_1k_2k=0
s_2k_4k=0
s_4k_8k=0
s_8k=0

idx=0

while true
do

   if (($idx >= 10000));then
       break
   fi

   tcpdump "tcp[20:2]=0x4854" -i eth0 -nn  -A -c 1 | sed "s/.*HTTP/HTTP/g" > tmp_http_header.log
   cat tmp_http_header.log >> http_header.log
   #notice ^M CTRL-V Shift-M
   #cat -v
   #sed -n '/HTTP/,/^^M/p' tmp_http_header.log
   #  ^M is special character
   sed -i -e 's/^^M$/vaynedu_test_http/g' tmp_http_header.log
   header_num=`cat tmp_http_header.log | grep  -A100 "HTTP" | grep -m1 -B100  "vaynedu_test_http" | grep -v "vaynedu_test_http" | wc -c `
  # echo $header_num

   if (($header_num < 512));then
       let s_512++
   elif (($header_num < 1024));then
       let s_512_1k++
   elif (($header_num < 2048));then
       let s_1k_2K++
       echo "vaynedu_1k_2k $header_num" >> http_header.log
   elif (($header_num < 4096));then
       let s_2k_4k++
       echo "vaynedu_2k_4k $header_num" >> http_header.log
   elif (($header_num < 8192));then
       let s_4k_8k++
       echo "vaynedu_4k_8k $header_num" >> http_header.log
   else
       let s_8k++
       echo "vaynedu_8k    $header_num" >> http_header.log
   fi

   let idx++
done

>count_result.txt
echo "http header size:"  >> count_result.txt
echo "[0, 512) : $s_512" >> count_result.txt
echo "(512,1k] : $s_512_1k" >> count_result.txt
echo "(1k, 2k] : $s_1k_2k"  >> count_result.txt
echo "(2k, 4k] : $s_2k_4k"  >> count_result.txt
echo "(4k, 8k] : $s_4k_8k"  >> count_result.txt
echo "(8k, ++] : $s_8k"  >> count_result.txt

注意注意^M是特殊字符是特殊字符

抓取1w个http请求,并且将这些头部保存下来,统计1w请求http头部大小在哪个区间,下面效果展示

未分类

未分类

Ubuntu 16.04 LTS ssh安装和配置

第一步:获取root权限

sudo -i

根据提示输入密码

第二步:更新源列表

sudo apt-get update

第三步:安装ssh

sudo apt-get install openssh-server

第四步:配置ssh

gedit /etc/ssh/ssh_config

注释掉 PermitRootLogin without-password
加入 PermitRootLogin yes

第五步:启动ssh服务

service ssh start

温馨提示:ssh默认端口号为22

CentOS监控ssh免密登录

ssh免密登录在带来方便的同时也带来一些问题,那就是不知道什么时间什么人利用ssh免密通道登录服务器了,为此我们需要在sshd的配置文件里设置好详细日志,以便日后回溯。

在CentOS里,sshd的日志文件是保存在/var/log/secure里的,如果不进行特殊设置的话,它只记录一些最简单的信息,比如什么时间哪个账号被人用免密登录的方式登录了,如果这个账号的authorized_keys里有很多key的话,这样的log没有办法告诉你客户到底是用哪个key登录的。

所以,我们需要在sshd的配置文件/etc/ssh/sshd_config文件里找到以下项LogLevel并把它改成LogLevel VERBOSE,这一项的缺省值是INFO,不够详细,所以我们需要把它改成啰嗦模式,这样可以记录更多信息。

改成VERBOSE并重启sshd(service sshd restart)后,我们会在日志文件里看到类似于这样的记录:

Apr 1 10:37:06 hostname sshd[5903]: Found matching RSA key: 83:67:b5:c7:bb:17:4d:06:ca:dc:8b:ca:85:cc:0c:b1

但这样的信息明显不同于我们在authorized_keys里存放的信息,那该怎么办呢?实际上,在sshd的日志文件里存储的只是我们authorized_keys的指纹信息fingerprint,不是真正的key,必须从authorized_keys反算出fingerprint来,才能做对比:

ssh-keygen -E md5 -lf /home/someuser/.ssh/authorized_keys

但是这样依然很麻烦,有没有办法直接告诉我日志里到底是谁登录的呢?为此我们还需要引入一个用Perl写的小程序点击预览。(原作者写的略有问题,在新版的CentOS里必须要求附加md5参数,为此我做了一些小的修改):

#!/usr/bin/perl -w
use strict;
use diagnostics;
use File::Temp;

# Matches Fingerprints from sshd logs (sshd on loglevel VERBOSE) against
# authorized_keys for the respective user.

die "Please specify input file!n" unless ($ARGV[0]);

my $fingerprints;

my $nav = File::Navigate->new($ARGV[0]);
# Store publickey login events
my @lines = @{$nav->find(qr/sshd[d+]: Accepted publickey for .+ from .+ port d+/)};

# Process all publickey login events
foreach(@lines){
    $nav->cursor($_);
    my $line = $nav->get();
    $line =~ /^(.{15}).+sshd[(d+)]: Accepted publickey for (.+) from (.+) port (d+)/;
    my $date = $1;
    my $pid  = $2;
    my $user = $3;
    my $ip   = $4;
    my $port = $5;
    my $fp   = "unknown"; # (yet)
    # Seek backwards to find matching fingerprint line
    my $sought = 0;
    while ((my $seekline = $nav->getprev()) and ($sought++ < 1000)){
        if ($seekline =~ /sshd[$pid]: Found matching .+ key: (.+)/){
            $fp = $1;
            last;
        }elsif($line =~ /sshd[$pid]: Connection from $ip port $port/){
            last;
        }
    }
    my $key = get_key($fp, $user);
    print ""$date";"$user";"$fp";"$key"n";
}

sub get_key{
    my $fp   = shift;
    $fp = "MD5:" . $fp;
    my $user = shift;

    # See if FP is cached
    if ($fingerprints->{$user}){
        if ($fingerprints->{$user}->{$fp}){
            return $fingerprints->{$user}->{$fp};
        }else{
            return "No matching key found.";
        }
    }

    # Else, generate fingerprints from users authorized_keys
    print STDERR "------> Reading keys for user $usern";
    my $home = (getpwnam($user))[7];
    open my $fh_in, "<$home/.ssh/authorized_keys" or warn "No such file: $home/.ssh/authorized_keysn";
    while (<$fh_in>){
        chomp;
        next unless (/^ssh-/);
        my $out_fh = File::Temp->new();
        print $out_fh "$_n";
        close $out_fh;
        my $fp_raw = `ssh-keygen -E md5 -lf $out_fh`;
        # Second field of output has the fingerpring
        my $fp = (split /s+/, $fp_raw)[1];
        $fingerprints->{$user}->{$fp} = $_;
    }
    if ($fingerprints->{$user}->{$fp}){
        return $fingerprints->{$user}->{$fp};
    }else{
        return "No matching key found.";
    }
}

package File::Navigate;
use strict;
use warnings;

=head1 NAME

File::Navigate - Navigate freely inside a text file

=head1 DESCRIPTION

The module is a glorified wrapper for tell() and seek().

It aims to simplify the creation of logfile analysis tools by
providing a facility to jump around freely inside the contents
of large files without creating the need to slurp excessive
amounts of data.

=head1 SYNOPSIS

  use File::Navigate;
  my $nav = File::Navigate->new('/var/log/messages');

  # Read what's below the "cursor":
  my $first = $nav->get;

  # Advance the cursor before reading:
  my $second = $nav->getnext;
  my $third  = $nav->getnext;

  # Advance the cursor by hand:
  $nav->next;
  my $fourth = $nav->get;

  # Position the cursor onto an arbitrary line:
  $nav->cursor(10);
  my $tenth  = $nav->get;

  # Reverse the cursor one line backward:
  $nav->prev;
  my $ninth  = $nav->get;

  # Reverse the cursor before reading:
  my $eigth  = $nav->getprev;

  # Read an arbitrary line:
  my $sixth  = $nav->get(6);

=cut

our @ISA       = qw(Exporter);
our @EXPORT_OK = qw();
our $VERSION   = '1.0';

=head1 CLASS METHODS

=head2 I<new()>

Open the file and create an index of the lines inside of it.

  my $mapper = File::Navigate->new($filename);

=cut

sub new($){
    my $class = shift;
    my $file;
    unless ($file = shift){
        die "No file specifiedn";
    }
    unless (-e $file){
        die "File not found: $filen";
    }
    unless (-r $file){
        die "File not readable: $filen";
    }
    my $self = {};
       $self->{'cursor'}         = 1;
       $self->{'lineindex'}      = {};
       $self->{'lineindex'}->{1} = 0;
    open my $fh, "$file"
        or die "Can't open $file: $!n";
    while (<$fh>){
        my $thisline = $.;
        my $nextline = $thisline + 1;
        $self->{'lineindex'}->{$nextline} = tell $fh;
    }
    $self->{'length'} = scalar(keys %{$self->{'lineindex'}}) - 1 ;
    $self->{'fh'} = $fh;
    bless $self;
}

=head1 OBJECT METHODS

=head2 I<count()>

Returns the number of lines in the file ("wc -l")

  my $lines = $nav->count;

=cut

sub length(){
    my $self = shift;
    return $self->{'length'};
}

=head2 I<cursor()>

Returns the current cursor position and/or sets the cursor.

  my $cursor = $nav->cursor();   # Query cursor position.
  my $cursor = $nav->cursor(10); # Set cursor to line 10

=cut

sub cursor($){
    my $self = shift;
    if (my $goto = shift){
        $self->{'cursor'} = $goto;
    }
    return $self->{'cursor'};
}

=head2 I<get()>

Gets the line at the cursor position or at the given position.

  my $line = $nav->get();   # Get line at cursor
  my $line = $nav->get(10); # Get line 10

=cut

sub get($){
    my $self = shift;
    my $fh   = $self->{'fh'};

    my $getline;
    $getline = $self->{'cursor'} unless ($getline = shift);

    if ($getline < 1){
        warn "WARNING: Seek before first line.";
        return undef;
    }elsif($getline > $self->{'length'}){
        warn "WARNING: Seek beyond last line.";
        return undef;
    }
    seek ($fh, $self->{'lineindex'}->{$getline}, 0);
    my $gotline = <$fh>;
    chomp $gotline;
    return $gotline;
}

=head2 I<next()>

Advance the cursor position by one line. Returns the new cursor position.
Returns I<undef> if the cursor is already on the last line.

  my $newcursor = $nav->next();

=cut

sub next(){
    my $self = shift;
    if ($self->{'cursor'} == $self->{'length'}){
        return undef;
    }
    $self->{'cursor'}++;
    return $self->{'cursor'};
}

=head2 I<prev()>

Reverse the cursor position by one line. Returns the new cursor position.
Returns I<undef> if the cursor is already on line 1.

  my $newcursor = $nav->prev();

=cut

sub prev(){
    my $self = shift;
    if ($self->{'cursor'} == 1){
        return undef;
    }
    $self->{'cursor'}--;
    return $self->{'cursor'};
}

=head2 I<getnext()>

Advance to the next line and return it.
Returns I<undef> if the cursor is already on the last line.

  my $newcursor = $nav->getnext();

=cut

sub getnext(){
    my $self = shift;
    $self->next or return undef;
    return $self->get;
}

=head2 I<getprev()>

Reverse to the previous line and return it:
Returns I<undef> if the cursor is already on line 1.

  my $newcursor = $nav->getprev();

=cut

sub getprev(){
    my $self = shift;
    $self->prev or return undef;
    return $self->get;
}

=head2 I<find()>

Find lines containing given regex. Returns array with line numbers.

  my @lines = @{$nav->find(qr/foo/)};

=cut

sub find($){
    my $self = shift;
    my $regex = shift;

    my @results;
    for (my $lineno = 1; $lineno <= $self->{'length'}; $lineno++){
        my $line = $self->get($lineno);
            if ($line =~ $regex){
            push @results, $lineno;
        }
    }
    return @results;
}

sub DESTROY(){
    my $self = shift;
    close $self->{'fh'};
}

=head1 EXAMPLE

I<tac>, the opposite of I<cat>, in Perl using File::Navigate:

  #!/usr/bin/perl -w
  use strict;
  use File::Navigate;

  foreach my $file (reverse(@ARGV)){
          my $nav = File::Navigate->new($file);
          # Force cursor beyond last line
          $nav->cursor($nav->length()+1);
          print $nav->get()."n" while $nav->prev();
  }

=head1 BUGS

Seems to lack proper error handling.

=head1 LIMITATIONS

Works only on plain text files. Sockets, STDIO etc. are not supported.

=head1 PREREQUISITES

Tested on Perl 5.6.1.

=head1 STATUS

Mostly harmless.

=head1 AUTHOR

Martin Schmitt <mas at scsy dot de>

=cut

1;

为此我们给它起名叫match-ssh-keys,赋予它可执行权限(chmod +x match-ssh-keys),然后把它搬到/usr/local/bin里(mv match-ssh-keys /usr/local/bin/),这样我们以后再想查谁通过sshd免密登录过服务器就方便了,我们只需要执行:

match-ssh-keys /var/log/secure

就可以了。

解决内网ssh连接速度很慢的解决方案

服务器相互ping是延时小,但ssh -p 端口号 内网IP 时发现很慢,好长时间才返回。把服务器改按以下方法修改相应配置,再ssh相互连接发现很快:

# vi /etc/ssh/sshd_conf
UseDNS no

GSSAPIAuthentication no

保存退出

#service sshd restart

使用inotify-tools与rsync构建实时备份系统

使用inotifywait监控文件变动

inotifywait是 inotify-tools 包中提供的一个工具,它使用 inotify API 来监控文件/目录中的变动情况。

在archlinux上,我们可以使用下面命令来安装

sudo pacman -S --noconfirm inotify-tools

平时 inotifywait 会挂起在那里,直到文件/目录发生了要引起关注的事件后,它会退出并输出事件发生的场所、事件的名称以及引起事件的文件(当事件发生在目录上时才会输出).

inotifywait 最常用的选项有两个,一个是 -r 一个是 -e ,其中:

-r
表示递归监控子目录中文件发生的事件

-e
指定要监控的事件列表。对于备份系统来说,只需要监控 modify、create和delete三种事件就行了。

比如,我们运行

inotifywait -r -e modify,create,delete /tmp

表示监控 /tmp 目录及其子目录中文件修改、文件创建和文件删除三种事件。

这时程序一直在挂起状态

[lujun9972@X61 ~]$ inotifywait -r -e modify,create,delete /tmp
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.

这时在 /tmp 目录下新建一个文件

touch /tmp/newFile

则 inotifywait 进程退出,并输出如下信息

/tmp/ CREATE newFile

使用rsync同步变动

rsync是一款快速增量备份工具。它的具有以下几个特点使得它很适合用作做备份的工具:

  • 增量备份,只会传输修改过的内容
  • 可以在传输过程中实时解压缩,减少带宽消耗
  • 可以保持原来文件的权限、事件、软硬链接
  • 即支持本机复制,也支持远程复制

rsync常用法为:

rsync -avz --delete  src/ foo:/data

其中

-a
表示archive mode,即备份目录下的所有内容(包括子目录中的内容),并且保持软链接、文件属性、文件修改事件、文件的所有者和宿主信息不变,并且同步字符/块设备以及命名socket和fifo等特殊文件。

-v
表示输出备份的详细信息

-z
表示传输时进行压缩

--delete
删除备份目的地里src中没有的文件

src/
表示要备份的是src目录下的所有内容,注意这里最后的 / 不能去掉,否则会把src目录本身备份过去

foo:/data
表示备份的目的地是foo主机下的 /data/ 目录

整合起来

接下来我们只需要用个 while 死循环把两个工具整合起来就行了,非常简单

#!/bin/bash

if [[ $# -ne 2 ]];then
    cat<<EOF
Usage $(basename $0) source_dir [host:]dest_dir
EOF
    exit 0
fi

source_dir=$1
dest_dir=$2
while :
do
    inotifywait -r -e modify,create,delete ${source_dir} && rsync -avz ${source_dir}/ ${dest_dir} --delete
done

这里有必要说明的是,虽然用 inotifywait 能探测出文件具体做了什么改动,但实际上我们根本不需要知道具体的改变是什么。

我们只需要知道有所改变了,然后具体改变了什么由 rsync 来自己处理就行了。

解决nginx反向代理缓存不起作用的问题

昨天尝试用nginx搭建nuget镜像服务器,镜像服务器需要两个功能:1)反向代理;2)内容缓存。

用nginx做反向代理,配置非常简单,只需在/etc/nginx/nginx.conf中添加一个包含proxy_pass的server设置:

server {
    listen       80;
    listen       [::]:80;
    server_name  镜像服务器主机名;
    location / {
        proxy_pass http://www.nuget.org;
    }
}

而添加缓存功能,配置稍微复杂些。

首先要创建一个用于存放缓存文件的文件夹,比如这里用 /data/nuget-cache 。

mkdir /data/nuget-cache

然后在nginx.conf的http设置部分添加proxy_cache_path设置:

proxy_cache_path /data/nuget-cache levels=1:2 keys_zone=nuget-cache:20m max_size=50g inactive=168h;
  • keys_zone指的是缓存空间名称。

  • max_size指的是缓存文件可以占用的最大空间。

  • inactive指的是如果一个缓存文件多长时间不被访问,就会被删除。

接着在server设置部分添加proxy_cache与proxy_cache_valid设置:

server {
    listen       80;
    listen       [::]:80;
    server_name  镜像服务器主机名;
    location / {
        proxy_pass http://www.nuget.org;
        proxy_cache nuget-cache;
        proxy_cache_valid 168h;
    }
}
  • proxy_cache设置的就是proxy_cache_path中keys_zone的值。

  • proxy_cache_valid设置的是缓存过期时间,比如这里168小时过期。

这样设置后运行nginx,发现只有少部分内容被缓存,大部分内容不能被缓存,比如下面的URL的响应内容就不能被缓存:

http://www.myget.org/F/aspnetvnext/api/v2/FindPackagesById%28%29?id=%27System.Linq%27

查看http响应头(http headers),发现了下面2个http header:

Cache-Control: private
Set-Cookie: ai_session=ad829b6c509946098fa7f8e32fada661|2015-06-24T03:52:38.2032109+00:00|2015-06-24T03:52:38.4219541
+00:00; expires=Wed, 24-Jun-2015 04:22:38 GMT; path=/

问题就是它们引起的,需要在nginx中通过proxy_ignore_headers设置忽略它们,设置方法如下:

server {
    listen       80;
    listen       [::]:80;
    server_name  镜像服务器主机名;
    location / {
        proxy_pass http://www.nuget.org;
        proxy_cache nuget-cache;
        proxy_cache_valid 168h;
        proxy_ignore_headers Set-Cookie Cache-Control;
        proxy_hide_header Cache-Control;
        proxy_hide_header Set-Cookie;
    }
}

修改 Nginx 服务器 WordPress 上传文件大小限制

默认情况下 WordPress 上传文件限制为 2M,如果有上传较大文件的需要,我们需要将上传文件的大小上限调大。

修改 PHP 配置文件

编辑 PHP 配置文件 php.ini ,查找以下字段:

$ sudo vi /etc/php.ini

post_max_size=8M 
upload_max_filesize=2M 

其中,post_max_size 参数表示 POST 数据所允许的最大大小,一般要设置的比upload_max_filesize大;upload_max_filesize 参数表示默认上传文件大小。

将其改为自己需要的值,例如:

post_max_size=80M
upload_max_filesize=50M

修改 Nginx 配置文件

修改当前网站的 Nginx 配置文件,这个文件一般在 /etc/nginx/conf.d 目录下,后缀名为 .conf,在 http{} 字段中添加以下内容:

client_max_body_size 50M;

完成上述修改后,重启 PHP 与 Nginx 使修改生效:

sudo service nginx restart
sudo service php-fpm restart

完成后 WordPress 上传文件的大小限制就变成 50M 了!

Nginx 使用 GeoIP 模块区分用户地区

检查 GeoIP 是否安装

首先需要确认当前安装的 Nginx 是否安装了 GeoIP 模块

$ nginx -V
nginx version: nginx/1.12.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --with-http_geoip_module --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-mail --with-mail_ssl_module --with-file-aio

如果版本信息中包含 –with-http_geoip_module,则说明已经支持该模块,如果不支持请往下看

安装 GeoIP

首先安装依赖

$ yum -y install zlib zlib-devel

安装 GeoIP

$ wget http://geolite.maxmind.com/download/geoip/api/c/GeoIP.tar.gz
$ tar -zxvf GeoIP.tar.gz
$ cd GeoIP-1.4.8
$ ./configure
$ make
$ make install

使用ldconfig将库索引到系统中

$ echo '/usr/local/lib' > /etc/ld.so.conf.d/geoip.conf
$ ldconfig

检查库是否加载成功

$ ldconfig -v | grep GeoIP
libGeoIPUpdate.so.0 -> libGeoIPUpdate.so.0.0.0
libGeoIP.so.1 -> libGeoIP.so.1.4.8
libGeoIPUpdate.so.0 -> libGeoIPUpdate.so.0.0.0
libGeoIP.so.1 -> libGeoIP.so.1.5.0

将 GeoIP 模块编译到 Nginx 中

根据你当前 Nginx 的安装参数带上 –with-http_geoip_module 重新编译

$ ./configure --user=nginx --group=nginx 
    --with-http_geoip_module 
    --with-http_ssl_module 
    --with-http_realip_module 
    --with-http_addition_module 
    --with-http_sub_module 
    --with-http_dav_module 
    --with-http_flv_module 
    --with-http_mp4_module 
    --with-http_gunzip_module 
    --with-http_gzip_static_module 
    --with-http_random_index_module 
    --with-http_secure_link_module 
    --with-http_stub_status_module 
    --with-mail 
    --with-mail_ssl_module 
    --with-file-aio
$ make && make install

或者重新安装

$ wget https://nginx.org/download/nginx-1.12.2.tar.gz
$ tar zxvf nginx-1.12.2.tar.gz
$ cd nginx-1.12.2
$ ./configure --user=nginx --group=nginx 
    --with-http_geoip_module 
    --with-http_ssl_module 
    --with-http_realip_module 
    --with-http_addition_module 
    --with-http_sub_module 
    --with-http_dav_module 
    --with-http_flv_module 
    --with-http_mp4_module 
    --with-http_gunzip_module 
    --with-http_gzip_static_module 
    --with-http_random_index_module 
    --with-http_secure_link_module 
    --with-http_stub_status_module 
    --with-mail 
    --with-mail_ssl_module 
    --with-file-aio
$ make && make install

使用 GeoIP

首先查看本地是否已有 GeoIP 数据库

$ cd /usr/local/share/GeoIP
$ ll
-rw-r--r--. 1 root root  1183408 Mar 31 06:00 GeoIP.dat
-rw-r--r--. 1 root root 20539238 Mar 27 05:05 GeoLiteCity.dat

如果没有这两个库,则手动下载

wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gzip GeoLiteCity.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
gzip GeoIP.dat.gz

将库地址配置到 nginx.conf 中这个位置

http{
    ...
    geoip_country /usr/local/share/GeoIP/GeoIP.dat;
    geoip_city /usr/local/share/GeoIP/GeoLiteCity.dat;
    server {
        location / {
            root /www;
            if( $geo_country_code = CN ){
                root /www/zh;
            }
        }
    }
}

其他参数

  • $geoip_country_code; – 两个字母的国家代码,如:”RU”, “US”。
  • $geoip_country_code3; – 三个字母的国家代码,如:”RUS”, “USA”。
  • $geoip_country_name; – 国家的完整名称,如:”Russian Federation”, “United States”。
  • $geoip_region – 地区的名称(类似于省,地区,州,行政区,联邦土地等),如:”30”。 30代码就是广州的意思
  • $geoip_city – 城市名称,如”Guangzhou”, “ShangHai”(如果可用)。
  • $geoip_postal_code – 邮政编码。
  • $geoip_city_continent_code。
  • $geoip_latitude – 所在维度。
  • $geoip_longitude – 所在经度。

nginx如何有效控制资源请求有效期及资源位置

nginx作为目前最流行的服务器端软件,成功有其必然的原因。苏南大叔的博客,服务器端容器也使用了nginx技术。在本文中,您将看到:“nginx的conf配置文件,如何有效控制资源请求”的相关文章。这些静态资源主要包括:img、js、css等常见类型,涉及的内容都是nginx的conf文件的高级用法。

禁用静态资源缓存

如果禁用了静态资源缓存的话,客户每次访问网站的时候,静态资源都是要从服务器端进行请求的,而不是从本地缓存中读取。

  • 可能有人会说了,谁会这么干啊。其实,确实有这样的需求的。比如:苏南大叔以前写过一个网速对比程序。要求不能从本地缓存读取到的数据,必须每次都从服务器请求数据。
  • 当然,也有人会说:可以修改网页代码中静态资源的地址,在其地址后面,增加个随机时间戳。这样,就可以有效避免读取本地缓存了。苏南大叔以前也这么干过,不过觉得还是不稳妥。修改代码比较麻烦。那么利用nginx的conf文件配置,就可以从服务器端进行设定了。

核心配置代码如下:

location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
  add_header Cache-Control no-store;
}
location ~ .*.(js|css)?$ {
  add_header Cache-Control no-store;
}

控制静态资源的缓存时长

不过一般来说,对于静态资源的缓存控制,一般是类似下面所示的。下面的单位d字样就是day天。

location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$ {
  expires 100d;
}
location ~ .*.(js|css)?$ {
  expires 30d;
}

expires指令用于控制HTTP应答中的“Expires”和“Cache-Control”Header头部信息,起到控制页面缓存的作用。

语法:expires [time|epoch|max|off]
默认值:off

  • expires <time>:可以使用正数或负数。“Expires”头标的值将通过当前系统时间加上设定time值来设定。
    time值还控制”Cache-Control”的值:负数表示no-cache,正数或零表示max-age=time
  • expires -1:指定“Expires”的值为当前服务器时间-1s,即永远过期。
  • expires epoch:指定“Expires”的值为 1 January,1970,00:00:01 GMT
  • expires max: 指定“Expires”的值为31 December2037 23:59:59GMT,”Cache-Control”的值为10年。
  • expires off:不修改“Expires”和”Cache-Control”的值

转移服务器端静态资源位置

假如,苏南大叔要请求同一个资源/demo/demo.png,如果nginx用的是不同的配置,则:

  • 如果设置的是:root /code/nginx/demo/,那么实际上的资源位置应该是/code/nginx/demo/demo/demo.png。
  • 如果设置的是:alias /code/nginx/demo/,那么实际上的字样位置应该被改写到/code/nginx/demo/demo.png。

下面的配置代码中,苏南大叔再一次演示如何使用root/alias进行nginx请求改写。

location ^~ /root/ {
    root  /code/nginx/root/ ;
}
location ^~ /alias/ {
    alias  /code/nginx/alias/ ;
}

未分类

未分类

拦截请求跳转到新的url

下面演示的是:拦截/baidu/下面的请求,然后永久性的permanent跳转到百度的搜索页面。当然,这个过程中,地址栏里面的url是发生变化的。其实这个小功能还是不错的,善加利用一下,就可以利用这种拦截特殊url的方式,做很多特殊的跳转动作。想象力由你来发挥了。

location ^~ /baidu/ {
    rewrite ^/baidu/(.*)$  https://www.baidu.com/s?wd=$1 permanent;
}

未分类

未分类

总结

nginx设置,是网站运维的一个必备技能点。如果能够掌握nginx的配置文件的写法,应该可以做到事半功倍的效果,这里仅仅总结了几点简单常见的nginx设置场景。