CORS

CORS on Nginx

The following Nginx configuration enables CORS, with support for preflight requests.

#
# Wide-open CORS config for nginx
#
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
}

Allow CORS in Laravel

When you have local development with some other applications trying to connect to your Laravel backend, you will notice errors CORS error on console. That means, you would need to setup CORS to be enabled for backend routes.

We achieve that by creating middleware

php artisan make:middleware Cors

Update the header returned in app/Http/Middleware/Cors.php

<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
  public function handle($request, Closure $next)
  {
    return $next($request)
      ->header("Access-Control-Allow-Origin", "*")
      ->header("Access-Control-Allow-Methods’, "GET, POST, PUT, DELETE, OPTIONS")
      ->header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Token-Auth, Authorization");
  }
}

You should update the appropriate value in returning headers.

Then, register in app/Http/kernel.php

protected $routeMiddleware = [
  "auth" => \App\Http\Middleware\Authenticate::class,
  "auth.basic" => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
  "guest" => \App\Http\Middleware\RedirectIfAuthenticated::class,
  "cors" => \App\Http\Middleware\Cors::class, // <-- add this line
];

Finally, any route that you want to enable CORS, just add this middleware on route registration.

Then, add test routers in routes/api.php

// http://docker.local/api/v1/base
// without auth
Route::group(['prefix' => 'v1',  'middleware' => ['api', 'cors']], function () {
 Route::get('/base', 'Controller@base')->name('api.v1.base');
});

// with auth
Route::group(['prefix' => 'v1',  'middleware' => ['auth:api', 'cors']], function () {
 Route::get('/base', 'Controller@base')->name('api.v1.base');
});

LINUX 用uniq命令—-过滤、统计重复行

例如文件 text.txt 里面有内容:

YYY
吴晶
吴晶
李双琦
李双琦
Tony蒋
Tony蒋
Nancy/Winnie
Chef沈
Chef沈
Chef 李
Chef 李
Aiken
Aiken

命令:查处文件中的重复行

sort ./test.txt | uniq -d 

去除重复行后输出,或者 -c 计算处每个重复行的数量

uniq ./test.txt
uniq -c test.txt 

只输出唯一行

uniq -u test.txt

PHP Apps in a Subdirectory in Nginx

What We’re Using

The server is Ubuntu 16.04, , we install Nginx 1.13 and PHP 7.2. The example PHP applications are Laravel 5.5.

PLUS Docker ENV: https://github.com/yao3060/docker

TL;DR

Here’s the working configuration to have two Laravel apps working, where one application exists in a subdirectory of another.

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/top/public;

    index index.html index.htm index.php;

    server_name _;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location /nested {
        alias /var/www/nested/public;
        try_files $uri $uri/ @nested;

        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_param SCRIPT_FILENAME $request_filename;
            fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        }
    }

    location @nested {
        rewrite /nested/(.*)$ /nested/index.php?/$1 last;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }
}

How This Works

Let’s cover some details of the above configuration to see what’s going on.

Project Locations

In this example, the application files of the two applications don’t actually exist within one another. The application top exists in /var/www/top while the “nested” application lives in /var/www/nested.

This is, in my opinion, the prefered setup in this case, as nesting application files where you “physically” put one project’s files inside of another’s gets really messy with most PHP applications’ use of a public directory as a web root.

Your case may change a bit depending on the applications of course, but that shouldn’t change too much of this guide.

The Basic Setup

We start with a basic server configuration, good for serving a single application:

server {
    listen 80 default_server;

    root /var/www/top/public;

    index index.html index.htm index.php;

    server_name _;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }
}

This excludes some stuff you might want in a production app (e.g. cache headers for static assets), but is enough to get a PHP application working fine.

The relevant parts to this guide are:

  • root – we define the web root that is used with application top
  • index – We define index.php as one of the default files to look for if no file is specified in the URI
  • location { try_files ... } – We use the standard try_files directive in a block that catches all URI’s. This looks to see if a file or directory sent in the URI exists within the root directory. If it does not exist, it goes to the index.php file, which we know for sure is in the root directory.

Any part of the URI is appended to the root directive. So a URI of /foo/bar will search for a file or directory /var/www/top/public/foo/bar. In combination with the indexdirective, it also seaches for /var/www/top/public/foo/bar/index.[html|htm|php].

More interestingly however, the try_files directive will send most requests (except those for static assets – js, css files) to /index.php. Just like with any other URI, that is getting appended to the root, so Nginx will look for /var/www/top/index.php.

The last location ~ \.php$ {...} block is used for any files ending in .php. It sends the file off to PHP-FPM for processing.

Adding an App in a Subdirectory

We run into a few issues when running a second app within a subdirectory. Let’s walk through them.

First, we know we want a second application to run in subdirectory /nested (the subdirectory is arbitrary, I just chose to name it “nested”). So, we create a location block for the “nested” location:

location /nested {

}

Now we can add to it to get our application running.

web root:

We know we have a separate web root for the nested project. Like me, your first inclination may be to set a root to point Nginx to /var/www/nested/public, but this doesn’t end up working! Instead, we need to use an alias:

location /nested {
    # We point the alias to the "nested" 
    # project's web root
    alias /var/www/nested/public;
}

An alias is similar to root, but it has different behavior.

Nginx combines the root + the given URI to find a file on the disk drive. For example, a URI /foo/bar will instruct Nginx to serve /var/www/top/public/foo/bar. Since that directory doesn’t exist, the try_files part tells Nginx to send the request to /var/www/top/public/index.php.

The included snippets/fastcgi-php.conf configuration takes care of parsing out /foo/bar as the intended URI that the PHP application uses as a route.

The alias does not behave exactly like this. In our example, the /nested URI is aliased to /var/www/nested/public. A URI of /nested will therefore look in /var/www/nested/public for a file to serve. A URI of /nested/foo will instruct Nginx to look in /var/www/nested/public/foo; the /nested portion is omitted.

Note that distinction – with that alias, Nginx does NOT look for files within /var/www/nested/public/nested/foo, like it would with the root directive.

try_files:

So, alias has the behavior we want – it won’t try to look for files inside of some nesteddirectory that does not exist. We still need to make a URI like /nested/foo serve from file /var/www/nested/public/index.php, so we have to add another try_files.

location /nested {
    alias /var/www/nested/public;
    try_files $uri $uri/ /index.php$is_args$args;
}

That looks very familiar! However, we’re going to have to do some more PHP things specifically in the /nested location, so let’s get a PHP handler in there also:

location /nested {
    alias /var/www/nested/public;
    try_files $uri $uri/ /index.php$is_args$args;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }
}

The PHP handler location block is nested within the location /nested {...} block so we can customize it a bit.

Note that I snuck something into the PHP location block there. I (re)set the SCRIPT_FILENAME FastCGI parameter to $request_filename. This normally is $document_root$fastcgi_script_name, which in our configuration would always point to /var/www/top/public/index.php – the wrong application!

Instead we use $request_filename, which has the following definition in the Nginx docs:

file path for the current request, based on the root or alias directives, and the request URI

So this takes the alias into account correctly, and will pass the correct path to the index.phpfile in our nested application.

It works?!

This will appear to work at first! Heading to URI /nested will work fine. What happens is /nested is aliased to /var/www/nested/public and try_files sends that to /index.php, which ends up correctly being /var/www/nested/public/index.php.

However, if our app has a defined route (foo, for example), and we try to head to URI /nested/foo to reach it, we receive a 404 error! Not only that, it’s a 404 page from the top level app!

This request ends up being handled by the outer PHP handler, which uses $document_root$fastcgi_script_name for the SCRIPT_FILENAME, thus pointing to file /var/www/top/public/index.php and being served by the top level app.

I’ve confirmed and tested the request is handled by the location /nested block, and is then sent to the wrong location ~ \.php$ {...} block. I’m not sure why this happens though! If you do, drop me a tweet @fideloper or email – chris AT this site’s domain.

To get around this issue, we rewrite the URI to put index.php in the correct spot in the eyes of Nginx.

rewrite:

To implement the rewrite, we’ll use a named location:

location /nested {
    alias /var/www/nested/public;
    try_files $uri $uri/ @nested;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
    }
}

location @nested {
    rewrite /nested/(.*)$ /nested/index.php?/$1 last;
}

We adjust try_files to send requests to @nested, and then define @nested as a named location block.

This location block rewrites the URI so /nested/foo becomes /nested/index.php/foo. The last directive tells Nginx to use the new, rewritten URI and match it against the other location blocks.

Nginx then re-reaches the location /nested {...} block, where it’s parsed correctly! The index.php file is in the correct location on the disk, and the included fastcgi-php.confconfigurations parse out the foo route from the rest of the URI as normal (via fastcgi_split_path_info, if you were curious).

Don’t forget the needed change to the SCRIPT_FILENAME FastCGI parameter explained above as well. That sends our correctly-parsed script file path to PHP-FPM.

Testing

Here’s what I did to create this scenario and test out the Nginx configuration:

# Ubuntu 16.04 Server

sudo add-apt-repository -y ppa:ondrej/php
sudo add-apt-repository -y ppa:nginx/development
sudo apt-get update

sudo apt-get install -y nginx php7.2-fpm php7.2-cli \
    php7.2-pgsql php7.2-sqlite3 php7.2-gd \
    php7.2-curl php7.2-memcached \
    php7.2-imap php7.2-mysql php7.2-mbstring \
    php7.2-xml php7.2-zip php7.2-bcmath php7.2-soap \
    php7.2-intl php7.2-readline php7.2-imagick php-msgpack php-igbinary

php -r "readfile('http://getcomposer.org/installer');" | sudo php -- --install-dir=/usr/bin/ --filename=composer

cd /var/www
sudo composer create-project laravel/laravel top
sudo composer create-project laravel/laravel nested

sudo chown -R www-data: top nested

Linux 使用私钥登录

  1. 生成ssh公钥密钥对:参考
root@0aedf4c047f8:~/.ssh# ssh-keygen -t rsa
生成ssh公钥密钥对

2. 进入/root/.ssh目录下, 将公钥复制到 authorized_keys 文件。

# cat id_rsa.pub >> authorized_keys
# chmod 600 authorized_keys

3. 下载私钥 id_rsa,这样,便可以通过私钥来免密登录服务器了!

现在可以在本地 docker 起一台ubuntu 虚拟机

## 安装一下 openssh-client
apt-get update -y && apt-get install openssh-client -y

##
## Run ssh-agent
##
eval $(ssh-agent -s)

# 将 私钥 id_rsa 文件同步到 docker 容器里的 /tmp 目录
# 然后 赋值 给 SSH_PRIVATE_KEY
SSH_PRIVATE_KEY="$(cat /tmp/rsa_key)"


##
## 把私钥添加到ssh-agent的高速缓存中
## We're using tr to fix line endings which makes ed25519 keys work
## without extra base64 encoding.
## https://gitlab.com/gitlab-examples/ssh-private-key/issues/1#note_48526556
##
echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null

##
## 创建 SSH 目录,赋予正确的权限
##
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh

##
## Use ssh-keyscan to scan the keys of your private server. Replace gitlab.com
## with your own domain name. You can copy and repeat that command if you have
## more than one server to connect to.
##
- ssh-keyscan gitlab.com >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts

# 登陆您的服务器
ssh -vvv root@test.domain.com

在 Ubuntu 16/18 上重置 MySQL 5.7 root 账户密码

apt install mysql-server, 莫名其妙的就装完了,都没有让我设置密码,现在只能通过其他方式来重置密码。

# Stop MySQL
sudo service mysql stop
# Make MySQL service directory.
sudo mkdir /var/run/mysqld
# Give MySQL user permission to write to the service directory.
sudo chown mysql: /var/run/mysqld
# Start MySQL manually, without permission checks or networking.
sudo mysqld_safe --skip-grant-tables --skip-networking &
# Log in without a password.
mysql -uroot mysql

然后就可以通过 SQL 修改 root 密码了

UPDATE mysql.user SET authentication_string=PASSWORD('root'), plugin='mysql_native_password' WHERE User='root' AND Host='%';

UPDATE mysql.user SET authentication_string=PASSWORD('root'), plugin='mysql_native_password' WHERE User='root' AND Host='localhost';

EXIT;
# Turn off MySQL.
sudo mysqladmin -S /var/run/mysqld/mysqld.sock shutdown
# Start the MySQL service normally.
sudo service mysql start

How To Install Oracle Java JDK 11 / 8 on Ubuntu 18.04 / Linux Mint 19

Today we will be going through the steps to install Oracle Java JDK 11 / 8 on Ubuntu 18.04. Java SDK is the base for the JAVA developers, and this guide will be more useful for them to build a development environment when they especially use Ubuntu.

Open up a terminal and switch to the root user.

sudo su -

OR

su -

Install Oracle Java JDK 11 / 8 on Ubuntu 18.04

We can install Oracle Java JDK in two ways,

Method 1: Install Oracle Java JDK 11 / 8 on Ubuntu 18.04 using Official Source

Method 2: Install Oracle Java JDK 11 / 8 on Ubuntu 18.04 using PPA

Method 1: Install Oracle Java JDK 11 / 8 on Ubuntu 18.04 using Official Source

You can download the Oracle JDK either using command line or browser. Recommend you to use the browser to download the Oracle JDK.

Download using browser

Oracle Java JDK 11: (Current)

Download Oracle JDK 11

Oracle Java JDK 10: (End of public updates)

Download Oracle JDK 10

Oracle Java JDK 8: (End of Public Updates – Jan 2019)

Download Oracle JDK 8

Oracle Java JDK 9: (End of Life)

Download Oracle JDK 9

Download using terminal

### Oracle Java JDK 11 ###

wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" https://download.oracle.com/otn-pub/java/jdk/11.0.1+13/90cf5d8f270a4347a95050320eef3fb7/jdk-11.0.1_linux-x64_bin.tar.gz

### Oracle Java JDK 8 ###

wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" https://download.oracle.com/otn-pub/java/jdk/8u191-b12/2787e4a523244c269598db4e85c51e0c/jdk-8u191-linux-x64.tar.gz

Extract the downloaded JDK archive using the tar command to the desired directory (Ex. /usr/)

tar -zxvf jdk-*

mv jdk* /usr/

Once you moved the java to the location you want, then you must run update-alternatives command to install the Java on your system.

### Oracle JDK 11 ### 

update-alternatives --install /usr/bin/java java /usr/jdk-11.*/bin/java 2

### Oracle JDK 8 ###

update-alternatives --install /usr/bin/java java /usr/jdk1.8.*/bin/java 2

Set the default java using the below command.

update-alternatives --config java

The above command would list all Java JDK installed on your system, like below.

There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                            Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      auto mode
  1            /usr/jdk-11.0.1/bin/java                         2         manual mode
  2            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      manual mode

Press  to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/jdk-11.0.1/bin/java to provide /usr/bin/java (java) in manual mode

If you require Oracle Java JDK 11, then choose the 1 and press enter.

Method 2: Install Oracle Java JDK 11 / 8 on Ubuntu 18.04 using PPA

Add the JAVA JDK PPA using the add-apt-repository comamnd.

### Oracle JDK 11 ### 

sudo add-apt-repository ppa:linuxuprising/java

### Oracle JDK 8 ###

sudo add-apt-repository -y ppa:webupd8team/java

Now, install Java JDK using the apt-get command.

### Oracle JDK 11 ###

sudo apt install -y oracle-java11-installer

### Oracle JDK 8 ###

sudo apt install -y oracle-java8-installer

During the installation, you would need to accept the Oracle binary licenses.

To set the default Java, install the below package according to your requirement.

### Oracle JDK 11 ###

sudo apt install -y oracle-java11-set-default

### Oracle JDK 8 ###

sudo apt install -y oracle-java8-set-default

Verify Java

Now, check the java version using the following command.

java -version

Output:

Oracle Java JDK 11:

java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)

Oracle Java JDK 8:

java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

Setup JAVA Environmental Variables

Some Java application installations require prior configuration of environmental variables like JAVA_HOME , JRE_HOME,etc.

To set JAVA environment variables, create a new file under /etc/profile.d directory.

sudo nano /etc/profile.d/javajdk.sh

Place the variables based on the JDK location and version.

JDK 11:

export PATH=$PATH:/usr/jdk-11.0.1/bin
export JAVA_HOME=/usr/jdk-11.0.1
export J2SDKDIR=/usr/jdk-11.0.1

JDK 8:

export PATH=$PATH:/usr/jdk1.8.0_191/bin
export JAVA_HOME=/usr/jdk1.8.0_191
export JRE_HOME=/usr/jdk1.8.0_191/jre/
export J2SDKDIR=/usr/jdk1.8.0_191
export J2REDIR=/usr/jdk1.8.0_191/jre

Load the environments into the current session.

source /etc/profile.d/javajdk.sh

That’s All.

nginx之proxy_pass指令完全拆解

一、proxy_pass的nginx官方指南

nginx中有两个模块都有proxy_pass指令。

  • ngx_http_proxy_moduleproxy_pass
语法: proxy_pass URL;
场景: location, if in location, limit_except
说明: 设置后端代理服务器的协议(protocol)和地址(address),以及location中可以匹配的一个可选的URI。协议可以是"http"或"https"。地址可以是一个域名或ip地址和端口,或者一个 unix-domain socket 路径。  
详见官方文档: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
URI的匹配,本文第四部分重点讨论。
  • ngx_stream_proxy_moduleproxy_pass
语法: proxy_pass address;
场景: server
说明: 设置后端代理服务器的地址。这个地址(address)可以是一个域名或ip地址和端口,或者一个 unix-domain socket路径。  
详见官方文档: http://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_pass

二、两个proxy_pass的关系和区别

在两个模块中,两个proxy_pass都是用来做后端代理的指令。
ngx_stream_proxy_module模块的proxy_pass指令只能在server段使用使用, 只需要提供域名或ip地址和端口。可以理解为端口转发,可以是tcp端口,也可以是udp端口。
ngx_http_proxy_module模块的proxy_pass指令需要在location段,location中的if段,limit_except段中使用,处理需要提供域名或ip地址和端口外,还需要提供协议,如”http”或”https”,还有一个可选的uri可以配置。

三、proxy_pass的具体用法

ngx_stream_proxy_module模块的proxy_pass指令

server {
    listen 127.0.0.1:12345;
    proxy_pass 127.0.0.1:8080;
}

server {
    listen 12345;
    proxy_connect_timeout 1s;
    proxy_timeout 1m;
    proxy_pass example.com:12345;
}

server {
    listen 53 udp;
    proxy_responses 1;
    proxy_timeout 20s;
    proxy_pass dns.example.com:53;
}

server {
    listen [::1]:12345;
    proxy_pass unix:/tmp/stream.socket;
}

ngx_http_proxy_module模块的proxy_pass指令

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

    # 正常代理,不修改后端url的
    location /some/path/ {
        proxy_pass http://127.0.0.1;
    }

    # 修改后端url地址的代理(本例后端地址中,最后带了一个斜线)
    location /testb {
        proxy_pass http://www.other.com:8801/;
    }

    # 使用 if in location
    location /google {
        if ( $geoip_country_code ~ (RU|CN) ) {
            proxy_pass http://www.google.hk;
        }
    }

    location /yongfu/ {
        # 没有匹配 limit_except 的,代理到 unix:/tmp/backend.socket:/uri/
        proxy_pass http://unix:/tmp/backend.socket:/uri/;;

        # 匹配到请求方法为: PUT or DELETE, 代理到9080
        limit_except PUT DELETE {
            proxy_pass http://127.0.0.1:9080;
        }
    }

}

四、proxy_pass后,后端服务器的url(request_uri)情况分析

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

    # 情形A
    # 访问 http://www.test.com/testa/aaaa
    # 后端的request_uri为: /testa/aaaa
    location ^~ /testa/ {
        proxy_pass http://127.0.0.1:8801;
    }
    
    # 情形B
    # 访问 http://www.test.com/testb/bbbb
    # 后端的request_uri为: /bbbb
    location ^~ /testb/ {
        proxy_pass http://127.0.0.1:8801/;
    }

    # 情形C
    # 下面这段location是正确的
    location ~ /testc {
        proxy_pass http://127.0.0.1:8801;
    }

    # 情形D
    # 下面这段location是错误的
    #
    # nginx -t 时,会报如下错误: 
    #
    # nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular 
    # expression, or inside named location, or inside "if" statement, or inside 
    # "limit_except" block in /opt/app/nginx/conf/vhost/test.conf:17
    # 
    # 当location为正则表达式时,proxy_pass 不能包含URI部分。本例中包含了"/"
    location ~ /testd {
        proxy_pass http://127.0.0.1:8801/;   # 记住,location为正则表达式时,不能这样写!!!
    }

    # 情形E
    # 访问 http://www.test.com/ccc/bbbb
    # 后端的request_uri为: /aaa/ccc/bbbb
    location /ccc/ {
        proxy_pass http://127.0.0.1:8801/aaa$request_uri;
    }

    # 情形F
    # 访问 http://www.test.com/namea/ddd
    # 后端的request_uri为: /yongfu?namea=ddd
    location /namea/ {
        rewrite    /namea/([^/]+) /yongfu?namea=$1 break;
        proxy_pass http://127.0.0.1:8801;
    }

    # 情形G
    # 访问 http://www.test.com/nameb/eee
    # 后端的request_uri为: /yongfu?nameb=eee
    location /nameb/ {
        rewrite    /nameb/([^/]+) /yongfu?nameb=$1 break;
        proxy_pass http://127.0.0.1:8801/;
    }

    access_log /data/logs/www/www.test.com.log;
}

server {
    listen      8801;
    server_name www.test.com;
    
    root        /data/www/test;
    index       index.php index.html;

    rewrite ^(.*)$ /test.php?u=$1 last;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/tmp/php-cgi.sock;
        fastcgi_index index.php;
        include fastcgi.conf;
    }

    access_log /data/logs/www/www.test.com.8801.log;
}

文件: /data/www/test/test.php

<?php
echo '$_SERVER[REQUEST_URI]:' . $_SERVER['REQUEST_URI'];

通过查看 $_SERVER[‘REQUEST_URI’] 的值,我们可以看到每次请求的后端的request_uri的值,进行验证。

小结

情形A和情形B进行对比,可以知道proxy_pass后带一个URI,可以是斜杠(/)也可以是其他uri,对后端request_uri变量的影响。
情形D说明,当location为正则表达式时,proxy_pass不能包含URI部分。
情形E通过变量($request_uri, 也可以是其他变量),对后端的request_uri进行改写。
情形F和情形G通过rewrite配合break标志,对url进行改写,并改写后端的request_uri。需要注意,proxy_pass地址的URI部分在情形G中无效,不管如何设置,都会被忽略。

Linux基本命令

arch 显示机器的处理器架构(1)
uname -m 显示机器的处理器架构(2)
uname -r 显示正在使用的内核版本
dmidecode -q 显示硬件系统部件 – (SMBIOS / DMI)
hdparm -i /dev/hda 罗列一个磁盘的架构特性
hdparm -tT /dev/sda 在磁盘上执行测试性读取操作
cat /proc/cpuinfo 显示CPU info的信息
cat /proc/interrupts 显示中断
cat /proc/meminfo 校验内存使用
cat /proc/swaps 显示哪些swap被使用
cat /proc/version 显示内核的版本
cat /proc/net/dev 显示网络适配器及统计
cat /proc/mounts 显示已加载的文件系统
lspci -tv 罗列 PCI 设备
lsusb -tv 显示 USB 设备
date 显示系统日期
cal 2007 显示2007年的日历表
date 041217002007.00 设置日期和时间 – 月日时分年.秒
clock -w 将时间修改保存到 BIOS

LINUX CP 命令详解

cp (复制档案或目录)

[root@linux ~]# cp [-adfilprsu] 来源档(source) 目的檔(destination)

[root@linux ~]# cp [options] source1 source2 source3 …. directory

参数:

-a :相当于 -pdr 的意思;

-d :若来源文件为连结文件的属性(link file),则复制连结文件属性而非档案本身;

-f :为强制 (force) 的意思,若有重复或其它疑问时,不会询问使用者,而强制复制;

-i :若目的檔(destination)已经存在时,在覆盖时会先询问是否真的动作!

-l :进行硬式连结 (hard link) 的连结档建立,而非复制档案本身;

-p :连同档案的属性一起复制过去,而非使用预设属性;

-r :递归持续复制,用于目录的复制行为;

-s :复制成为符号连结文件 (symbolic link),亦即『快捷方式』档案;

-u :若 destination 比 source 旧才更新 destination !

最后需要注意的,如果来源档有两个以上,则最后一个目的文件一定要是『目录』才行!

范例:

范例一:将家目录下的 .bashrc 复制到 /tmp 下,并更名为 bashrc

[root@linux ~]# cd /tmp

[root@linux tmp]# cp ~/.bashrc bashrc

[root@linux tmp]# cp -i ~/.bashrc bashrc

cp: overwrite `basrhc’? n

# 重复作两次动作,由于 /tmp 底下已经存在 bashrc 了,加上 -i 参数,

# 则在覆盖前会询问使用者是否确定!可以按下 n 或者 y 呢!

# 但是,反过来说,如果不想要询问时,则加上 -f 这个参数来强制直接覆盖!

范例二:将 /var/log/wtmp 复制到 /tmp 底下

[root@linux tmp]# cp /var/log/wtmp .
[root@linux tmp]# ls -l /var/log/wtmp wtmp

-rw-rw-r– 1 root utmp 71808 Jul 18 12:46 /var/log/wtmp

-rw-r–r– 1 root root 71808 Jul 18 21:58 wtmp

# 注意到了吗?!在不加任何参数的情况下,档案的所属者会改变,连权限也跟着改变了~

# 这是个很重要的特性!要注意喔!还有,连档案建立的时间也不一样了!

# 如果您想要将档案的所有特性都一起复制过来,可以加上 -a 喔!

[root@linux tmp]# cp -a /var/log/wtmp wtmp_2

[root@linux tmp]# ls -l /var/log/wtmp wtmp_2

-rw-rw-r– 1 root utmp 71808 Jul 18 12:46 /var/log/wtmp

-rw-rw-r– 1 root utmp 71808 Jul 18 12:46 wtmp_2

# 瞭了吧!整个资料特性完全一模一样ㄟ!真是不赖~这就是 -a 的特性!

范例三:复制 /etc/ 这个目录下的所有内容到 /tmp 底下

[root@linux tmp]# cp /etc/ /tmp

cp: omitting directory `/etc’
[root@linux tmp]# cp -r /etc/ /tmp

# 还是要再次的强调喔! -r 是可以复制目录,但是,档案与目录的权限会被改变~

# 所以,也可以利用 cp -a /etc /tmp 来下达指令喔!

范例四:将范例一复制的 bashrc 建立一个连结档 (symbolic link)

[root@linux tmp]# ls -l bashrc

-rw-r–r– 1 root root 395 Jul 18 22:08 bashrc

[root@linux tmp]# cp -s bashrc bashrc_slink

[root@linux tmp]# cp -l bashrc bashrc_hlink

[root@linux tmp]# ls -l bashrc*

-rw-r–r– 2 root root 395 Jul 18 22:08 bashrc

-rw-r–r– 2 root root 395 Jul 18 22:08 bashrc_hlink

lrwxrwxrwx 1 root root 6 Jul 18 22:31 bashrc_slink -> bashrc

# 那个 bashrc_slink 是由 -s 的参数造成的,建立的是一个『快捷方式』,

# 所以您会看到在档案的最右边,会显示这个档案是『连结』到哪里去的!

# 至于那个 bashrc_hlink 有趣了!建立了这个档案之后, bashrc 与 bashrc_hlink

# 所有的参数都一样,只是,第二栏的 link 数改变成为 2 了~而不是原本的 1 喔!

# 这两种连结的方式的异同,我们会在下一章里面进行介绍的!

范例五:若 ~/.bashrc 比 /tmp/bashrc 新才复制过来

[root@linux tmp]# cp -u ~/.bashrc /tmp/bashrc

# 这个 -u 的特性,是在目标档案与来源档案有差异时,才会复制的。

# 所以,比较常被用于『备份』的工作当中喔! ^_^

范例六:将范例四造成的 bashrc_slink 复制成为 bashrc_slink_2

[root@linux tmp]# cp bashrc_slink bashrc_slink_2

[root@linux tmp]# ls -l bashrc_slink*

lrwxrwxrwx 1 root root 6 Jul 18 22:31 bashrc_slink -> bashrc

-rw-r–r– 1 root root 395 Jul 18 22:48 bashrc_slink_2

# 这个例子也是很有趣喔!原本复制的是连结档,但是却将连结档的实际档案复制过来了

# 也就是说,如果没有加上任何参数时,复制的是源文件,而非连结文件的属性!

# 若要复制连结文件的属性,就得要使用 -d 或者 -a 的参数了!

范例七:将家目录的 .bashrc 及 .bash_history 复制到 /tmp 底下

[root@linux tmp]# cp ~/.bashrc ~/.bash_history /tmp

# 可以将多个数据一次复制到同一个目录去!

这个 cp 的功能很多,而由于我们常常在进行一些数据的复制,所以也会常常用到这个指令的。 一般来说,我们如果去复制别人的数据 (当然,该档案您必须要有 read 的权限才行啊! ^_^) 时, 总是希望复制到的数据最后是我们自己的,所以,在预设的条件中, cp 的来源档与目的档的权限是不同的,目的档的拥有者通常会是指令操作者本身。举例来说, 上面的范例二中,由于我是 root 的身份,因此复制过来的档案拥有者与群组就改变成为 root 所有了! 这样说,可以明白吗?! ^_^

由于具有这个特性,因此,当我们在进行备份的时候,某些需要特别注意的特殊权限档案, 例如密码文件 (/etc/shadow) 以及一些设定档,就不能直接以 cp 来复制,而必须要加上 -a 或者是 -p 等等可以完整复制档案权限的参数才行!另外,如果您想要复制档案给其它的使用者, 也必须要注意到档案的权限(包含读、写、执行以及档案拥有者等等), 否则,其它人还是无法针对您给予的档案进行修订的动作喔!注意注意!

至于上面的范例当中,第四个范例是最有趣的,使用 -l 及 -s 都会建立所谓的连结档 (link file), 但是这两种连结档确有不一样的展现情况。这是怎么一回事啊? 那个 -l 就是所谓的 hard link ,至于 -s 则是 symbolic link ,鸟哥这里先不介绍, 因为这个涉及 i-node 的相关知识,我们还没有介绍到,下一章再来讨论这个 link 的问题喔! 总之,由于 cp 有种种的档案属性与权限的特性,所以,在复制时,您必须要清楚的了解到:

• 是否需要完整的保留来源档案的信息?

• 来源档案是否为连结档 (symbolic link file)?

• 来源档是否为特殊的档案,例如 FIFO, socket 等?

• 来源文件是否为目录?

.htaccess 完全手册

1.时区设置

有些时候,当你在PHP里使用date或mktime函数时,由于时区的不同,它会显示出一些很奇怪的信息。下面是解决这个问题的方法之一。就是设置你的服务器的时区。你可以在这里找到所有支持的时区的清单。

[code]SetEnv TZ Australia/Melbourne[/code]

2. 搜索引擎友好的301永久转向方法

为什么这是搜索引擎友好的呢?因为现在很多现代的搜索引擎都有能根据检查301永久转向来更新它现有的记录的功能。
继续阅读.htaccess 完全手册