nginx:反向代理实例

概述

这节其实是上一篇nginx教程的补充,因为有朋友看了之后对于反向代理那块还有点疑问.所以这边就举一个简单的例子(负载均衡).本来是想加上一些docker的知识的,但是在准备这篇文章的时候我的vps遭GFW三杀.所以浪费了一部分时间,恰好之前群里的一位朋友的搬瓦工vps也惨遭封禁,当时我还很轻松的告诉他迁移机房就可以了,当然结果肯定是啪啪打脸(果然还是我很傻很天真).所以在后半部分会提到一种解决方案(其实就是提工单后得出的结论).所以废话不说,进入正题吧~

nginx反向代理

上一篇文章提到了反向代理的概念.概念其实很简单,但是实际上有什么应用呢?
有个最简单也是很实用的例子,也就是负载均衡.作为反向代理的nginx在收到请求后按照一定规则再分发给下游的服务器.在这里对服务端而言客户端是明确的,并且通常配置的时候会带上realip.但是对于客户端来讲却不知道请求最后落到了哪台机器,这就是一个常见的反向代理的场景.这里并没有其他可以补充的知识,在nginx的官网上都是有相关介绍的.
这就着重以一个例子来实现.

这边会借助docker来实现这个例子.
最简单的一个例子就是两个服务容器一个nginx容器.
nginx容器就是直接使用官方镜像即可.

首先是server的代码,go语言编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
log.Println(r)
hostName, _ := os.Hostname()
w.Write([]byte(fmt.Sprintf("server:%s\n", hostName)))
return
})
log.Println("start...")
log.Panic(http.ListenAndServe(":8081", nil))
}

本身没什么难度,主要是会输出自己的hostname,这个在后面帮助我们区分实际访问的服务器.

然后go build 编译即可,根据自己的实际需求选择编译条件.这里我提供了现成的docker镜像,地址为(https://cloud.docker.com/u/evanshao/repository/docker/evanshao/lbserver),

就不多赘述了.
然后是Dockerfile

1
2
3
4
FROM debian
MAINTAINER evan
COPY server /
ENTRYPOINT ["./server"]

这个也很简单,就是借助debian基础镜像运行编译好的server.

然后是nginx配置(已经提供了镜像,地址是:https://cloud.docker.com/u/evanshao/repository/docker/evanshao/lbnginx).

这里可以参考上一篇文章的基础配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#user nobody;
worker_processes 4; # 按照机器情况定
events {
worker_connections 10240; # 按照机器情况定
}
http{
include mime.types;
default_type application/json; # 按照自己服务设置
error_page 500 502 503 504 /50x.html;
error_page 404 /404.html; # 这个自己写了放到html目录下,不然应该是nginx代码里写死的
resolver 114.114.114.114;
# 定义日志格式 这个别名是main
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 30;
include sites/*.http.conf; # 具体的server放在这里
}

重点是sites下需要两个新建的配置文件,
一个是ups.http.upstream:

1
2
3
4
upstream test_server{
server serverA:8081;
server serverB:8081;
}

这里其实是有两个注意点的,一个是serverA 这个是配合后面的dockerDNS使用的,还有个自然是端口号,和server程序监听的端口号一致.

另外一个文件是 ups.http.conf,这里在开头引用了upsream文件,并利用proxy_pass实现了转发.

1
2
3
4
5
6
7
8
9
10
11
12
include sites/ups.http.upstream;
server{
listen 80 default_server;
server_name localhost;
access_log logs/ups.log main;
location /{
set $upstream_host $host;
proxy_pass http://test_server;
}
}

这边是Dockerfile,myconf下就是上面的文件nginx.conf以及sites文件夹,sites里是其他两个文件.另外还创建了一个空的logs文件夹

1
2
3
4
5
FROM nginx
MAINTAINER evan
COPY myconf/ /etc/nginx
EXPOSE 80
ENTRYPOINT ["nginx","-g","daemon off;"]

到这里实验环境就准备好了,下面其实就是docker部分了,时间有限,这里仅仅提下使用方法.如果docker没有安装的话可以参考官方文档进行操作,后面有机会我也会开始写一些docker的简单教程~

上文提到的dockerDNS其实是docker提供的一种容器间通信的方法.具体的就不赘述了,如果有兴趣的话可以自行搜索或者等我的blog哦.
首先我们要创建自己的docker子网

1
docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net

这里相当于创建了一个局域网,网段是172.22.16.然后在运行server和nginx容器的时候我会把他们都指定到这个网段,这样才能保证局域网内各容器的网络通信.
接下来首先启动两台server容器

1
docker run -itd --rm --name serverA --hostname serverA --network=my_net evanshao/lbserver

1
docker run -itd --rm --name serverB --hostname serverB --network=my_net evanshao/lbserver

这里用--hostname 指定机器的host配合server的取值,--name相当于指定局域网内的通信域名,这里需要注意的是--name 指定的才是我们访问的域名,这里我顺手写成和hostname一样的了,不要混淆.

然后我们需要启动nginx

1
docker run -itd --rm --name lbnginx -p 80:80 --network=my_net evanshao/lbnginx

这时候实验环境就已经搭建完成了,我们通过浏览器访问http://192.168.31.147/test就可以看到效果了:

sorry,the pic is missing

刷新就变成

sorry,the pic is missing

这边配置默认应该是轮询,当你停掉一个容器的时候就会只访问到活着的那台机器了.
这里如果没时间自己操作的话,直接按照我上面的三条docker run命令执行即可.
后面可以慢慢还原.

这里写的有些粗略了,因为上一篇文章已经有提到一些nginx关键字的用法,官方也写得很详细了.主要还是展示下如果通过docker展现这一场景,后续我也会慢慢补充一些docker的知识,希望到时候能对你们有所帮助.

搬瓦工vps被墙

接下来就是插播的一条小tip吧,如果有买了搬瓦工vps被墙的朋友,可以尝试我这边的方法,也算一定程度上的止损吧,总比直接废弃的好.
首先现象就是ping通但是ssh等都没法过去,通过站长之家的端口扫描发现常用端口全部显示关闭.这时候通过在线的控制台爬上去发现sshd,iptables等却全部ok.这就很诧异了.其实这时候已经觉得是被GFW墙了,但是本着谨慎的原则我给搬瓦工提了工单.这里得夸下搬瓦工,响应速度出奇的快,虽然可能是自动回复,毕竟结尾写着This is an automatic reply..不过我那蹩脚的英文,他能这么快通过关键字响应过来也是很厉害的啦.如果是人工回复自然是点个赞,邮件回复推测可能是我被GFW墙了,同时给了个境外的在线端口扫描网站,结果发现在境外所有端口全部ok.这时候根据邮件里的建议只能换IP了.等GFW解封那个建议还是直接无视好了…这边是我觉得可(免)行(费)的一条建议的截图

sorry,the pic is missing

大体就是每10周可以免费换一次IP(所以还是别随便自己搭梯子了),其中先登录对应vps的KiwiVM,这里应该是获取到cookie,session或者token一类的东西,然后在当前地址栏里访问https://kiwivm.64clouds.com/main-exec.php?mode=blacklistcheck

这边会提示你检测ip是不是被ban了,检测完成后如果被ban了会有一个免费更换ip的按钮,点击就ok了.实测有效.

另外还有个付费更换IP的地址,我也贴下吧,自己取舍~

https://bwh8.net/ipchange.php

这次内容有点短,但还是希望能对大家有所帮助,更希望大家通过我的文章能起个头,看一些之前自己没有接触过的东西,这也是我写博客的目的.就像最近的几篇文章,我的博客内容不会很深入,但是我会尽可能尝试来包含不同领域的知识.当然也正因为如此,如果文章中有错误,欢迎指正给留言~

最后祝大家新年快乐,新的一年心想事成~

客官扫码领红包哟~