这里记录下docker部署的nginx,访问宿主机端口报502的问题,以及解决思路。
一、防火墙
- 首先确定宿主机防火墙是否打开了。如果防火墙关闭状态,则容器内应该可以直接访问宿主机的IP+端口。
比如我们的测试环境(Centos 7),防火墙是关闭的。
查看防火墙状态:
firewall-cmd --state
或者systemctl status firewalld
如果显示Active:actice(running)
则表示防火墙为开启状态。
防火墙关闭状态:
一般测试环境为了方便,直接将防火墙关闭了,这样在我们平时开发和测试的时候,确实会方便一些,但是有时候就是因为防火墙的原因,导致我们的程序在上了生产之后,出现莫名其妙的问题。
明明测试环境就是正常的,怎么生产就不好使了。。。。。。
如果防火墙是开启状态,那么我们就要开放特定的端口了。
firewall-cmd --zone=public --add-port=80/tcp --permanent
--zone #作用域
--add-port=80/tcp #添加端口,格式为:端口/通讯协议
--permanent #永久生效,没有此参数重启后失效
重启防火墙:systemctl restart firewalld.service
查看开放端口:
netstat -ntlp
firewall-cmd --list-ports
查看端口占用情况:lsof -i:端口号
lsof -i:8000
下面就是nginx的问题了。
二、使用虚拟IP进行容器内核宿主机通信
由于我这里使用的是docker安装的nginx,并且自定义了配置文件。
所以在进行路由转发和配置域名时,直接改配置文件即可。
首先是配置域名,配置域名很简单,只需要按照域名供应商提供的方法,将秘钥和key文件弄出来,然后放到nginx可以访问的路径下,将路径配置到conf的文件里面。
这里贴上现在用的配置,仅供参考,照搬不一定好使。
首先是定义监听80端口的配置文件:default.conf
upstream cavdWeb {
server 172.17.0.1:9999;
}
server {
listen 80;
server_name cavd.org.cn;
charset utf-8;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index safety-project/index.html index.htm;
}
location /web{
proxy_pass http://cavdWeb/web;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_redirect default;
}
#location /download/ {
# alias /opt/upload/;
# autoindex on;
#}
}
上面定义了一个 upstream cavdWeb
这个玩意就是我们下面进行固定前缀动态代理到别的端口或者IP所用到的。
这里面的IP:172.17.0.1
不是宿主机的IP。这点坑了我好久。
这个IP为docker和宿主机通信的IP,是一个虚拟的IP,查询方式是直接看 ifconfig
里的docker0
如果防火墙是关闭状态,直接写宿主机的IP和端口,可以直接访问,如果防火墙开机状态,则直接nginx启动失败。具体失败的日志可以使用docker logs --since 5m 容器ID
查看,其中 5m表示最近5分钟的日志。
然后是监听443的配置文件:https.conf
#upstream cavdWeb {
# #server 192.168.5.288:9999;
# server 172.17.0.1:9999;
#}
server {
listen 443 ssl;
server_name www.baidu.com;
#ssl on;
ssl_certificate /etc/nginx/cert/server.pem;
ssl_certificate_key /etc/nginx/cert/server.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!RC4:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!EXP:+MEDIUM;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
index safety-project/index.html index.htm;
}
location /web{
proxy_pass http://cavdWeb/web;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_redirect default;
}
}
其中:
ssl_certificate /etc/nginx/cert/server.pem;
ssl_certificate_key /etc/nginx/cert/server.key;
为存放https证书的路径及文件名。这里的路径需要保证nginx可以访问到。
[warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead
如果看到nginx日志里面包含上面的提醒,是因为nginx从1.18版本后,nginx提示ssl这个指令已经不建议使用,要使用listen ... ssl替代。所以看到上面配置文件 ssl on
这行给注释掉了,开头使用 listen 443 ssl
意思就是如果是直接安装的,设置绝对路径即可,如果是docker安装的,需要放在挂载的目录下面,保证nginx可以访问到。
另外,upstream cavdWeb
这个玩意 同一个名称在nginx下面只能定义一次,否则会启动失败。
刚开始我天真的将 upstream cavdWeb 中的地址定义为宿主机的IP或者127.0.0.1就可以了,结果启动之后,访问一直是502 Bad Gayteway
,或者可以从日志中看到:host not found in upstream "xxxxxxx"
在搜了半天网上的答案都是,首先看下服务端口是否正常,如果服务关闭了,确实是会出现502的错误。我看到这的时候,就没有想到,服务没开跟服务开了 访问不到,不是一回事么,结果倒腾了半天。。。。。。
最后贴上我的nginx的配置文件:nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
这里直接将 /etc/nginx/conf.d
路径下的所有conf结尾的配置文件都自动引入了。
启动docker镜像的命令:
docker run --privileged=true \
--restart=always \
--name nginx \
-d -p 80:80 \
-d -p 443:443 \
-v /usr/soft/nginx/html:/usr/share/nginx/html \
-v /usr/soft/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /usr/soft/nginx/conf.d:/etc/nginx/conf.d \
-v /usr/soft/nginx/cert:/etc/nginx/cert \
-v /opt/upload:/opt/upload \
192.168.104.51:5000/huaun/nginx:test
此处用的镜像是在网上找的,然后打了自己的镜像仓库tag。
这里将80和443端口映射出来,然后用-v将需要用到的几个目录挂载出来。