YOLO813

Nginx挂载两个域名测试

    目标:一台云服务器,两个域名,通过nginx,分别指向同服务器上的两个Django网站,并分别配置ssl证书。

    先下载nginx:

yum -y install openssl openssl-devel
yum -y install gcc pcre-devel zlib zlib-devel
wget http://nginx.org/download/nginx-1.18.0.tar.gz -P /usr/src
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
make && make install

熟悉的欢迎界面


    配置nginx服务脚本,方便控制nginx

vim /usr/lib/systemd/system/nginx.service
[Unit]
# 20210310 zhangxiaofei
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
# Nginx will fail to start if nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true
[Install]
WantedBy=multi-user.target
systemctl daemon-reload # 重启以生效

 

配置elinks,无缓存测试

yum install elinks lynx
elinks ip -source

 

重温nginx系列学习文章

 

 

    两个域名均以A记录类型指向测试服务器IP 111.22.44.121(下称X)。将TTL设置为最短600,方便快速生效。

    分别测试两个域名,可以看到已经生效

elinks *****b.com -source
elinks *****3.com -source


    开始制作两个测试html文件,分别命名为WEB1,WEB2

cd /usr/local/nginx/html
mkdir web1 web2
echo "web1" > web1/index.html; echo "web2" >web2/index.html

    配置nginx文件server段,为了测试方便,我是直接在nginx.conf文件上进行修改,大概在34行左右,我将原有server段修改如下,并增加了一个server段

server{
    listen     80;
    server_name domain1.com;
    location /{
      root html/web1;
      index index.html;
    }
}
server {
    listen       80;
    server_name  domain2.com;
    location /{
        root   html/web2;
        index  index.html index.htm;
    }
}
/usr/local/nginx/sbin/nginx -t

显示syntax is ok,那么可以重启nginx服务了。

systemctl restart nginx.service

    此时在服务器上,测试如下

elinks host1.com -source
elinks host2.com -source


    到这里,基本就可以确定,不同的域名可以解析到同一台云服务器上(单一公网IP),利用nginx对80端口的监听,分配到不同的网页内容,这也是预料之中的,不然nginx如何与如日中天的Apache抗衡呢。

 

通过uwsgi挂载不同项目

    首先,需要制作一个测试的django项目。为了仿制正式环境,还是配置了一个python的虚拟环境,因为我的服务器版本比较高,centos8.2,所以如下命令安装比较顺畅。

pip3 install virtualenvwrapper
vim /etc/profile
# 在末尾加入以下内容
VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
# 保存后让其生效
source /etc/profile

    创建虚拟环境

mkvirtualenv web-3; mkvirtualenv web-b;lsvirtualenv

    分别在两个虚拟环境中配置Django

pip install django==3.1.7

    在本地创建一个django项目,待会第二个项目类似,这里主要是测试nginx与uwsgi的对接

django-admin startproject domainB

打开url配置文件,将其完全改写如下

cd domainB/domainB
vim urls.py
from django.urls import path
from django.http import HttpResponse

def index(request):
    return HttpResponse("domain ****B")

urlpatterns = [
    path('', index),
]

    第二个项目

django-admin startproject domain3

    只需要修改上方的HttpResponse内容,方便待会测试区分

def index(request):
    return HttpResponse("33333  domain")

    这样我就得到了两个可以用于测试的django项目,将其传到云服务上的srv目录下,方便待会指定路径

ls /srv/
>> domain3  domainB

    安装、配置uwsgi(uwsgi必须安装在系统级别的Python环境中)

pip install uwsgi

报错如下:

我的python版本

Python 3.6.8 (default, Mar 19 2021, 05:13:41)

安装相关依赖如下:

yum install gcc python36-devel

再次安装uwsgi即可。

    测试uwsgi是否正常工作,我当前所在路径

/srv/domain3
uwsgi --http :8000 --module domain3.wsgi --venv=/root/.virtualenvs/web-3

    几个注意事项,http和:8000之间有空格,domain3.wsgi的是wsgi.py文件所在的文件夹名(别瞎改名),而--venv指向的是虚拟环境所在路径。

    这个时候访问服务器公网IP的8000端口,应该可以看到网页内容

elinks http://101.33.66.170:8000 -source
33333  domain

    如果你想在公网进行访问,记得修改django项目配置文件的ALLOWED_HOSTS

ALLOWED_HOSTS = ["*"]

    可以看到uwsgi正常工作,由于这一长串的参数启动比较麻烦,所以,写一个ini配置文件来启动,当前目录/srv/domain3

touch demo1.ini
vim demo1.ini
[uwsgi]
chdir = /srv/domain3
module = domain3.wsgi
http = :8000
home = /root/.virtualenvs/web-3

接下来启动配置文件,网站可以正常访问

uwsgi demo1.ini

那么配置文件已经配置成功,修改配置文件,将内部通讯换成更为高效的sock文件:

[uwsgi]
chdir = /srv/domain3
module = domain3.wsgi
#http = :8000
home = /root/.virtualenvs/web-3
master          = true
# 最大数量的工作进程
processes       = 4
# socket文件路径,绝对路径,会自动创建
socket          = /srv/domain3/domain3.sock
# 设置socket的权限
chmod-socket    = 666
# 退出的时候是否清理环境
vacuum          = true

    依葫芦画瓢,制作第二个项目的ini配置文件

cp /srv/domain3/demo1.ini /srv/domainB/demo2.ini
[uwsgi]
chdir = /srv/domainB
module = domainB.wsgi
home = /root/.virtualenvs/web-b
master          = true
processes       = 4
socket          = /srv/domainB/domainB.sock
chmod-socket    = 666
vacuum          = true

 

    开始配置nginx配置文件,将之前配置的两个测试server删除掉

html{
  upstream demo1site {
    # 设定目录自动创建,即ngnix和uwsgi通讯的sock位置
    # 一定要和demo1.ini中定义的socket一致
    server unix:///srv/domain3/domain3.sock;
  }
  upstream demo2site {
    server unix:///srv/domainB/domainB.sock;
  }
 
  server{
    listen     80;
    server_name *****b.com;
    # 最后,发送所有非静态文件请求到django服务器
    location / {
      # 这个uwsgi_pass对应的参数一定要和upstream定义的一样
      uwsgi_pass  demo1site;
      # uwsgi_params文件地址
      include     /usr/local/nginx/conf/uwsgi_params;
      }
    }
  server {
      listen       80;
      server_name  z***3.com
     location / {
        uwsgi_pass  demo2site;
        include   /usr/local/nginx/conf/uwsgi_params;
     }
    }
}

    配置完成之后,重启nginx,并启动uwsgi

uwsgi demo1.ini
uwsgi demo2.ini

    访问两个域名,成功返回了各自网站的内容


    但是这样还有点小问题,就是两个网站的日志混杂在一起,检查起来不是很方便,所以可以考虑将日志处理一下,在原来的nginx的配置文件http段中,增加一行包含代码

mkdir conf.d
vim nginx.conf
include conf.d/*.conf;

在conf.d目录下新建web1.conf和web2.conf文件,web1.conf文件如下

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';
upstream demo1site {
    server unix:///srv/domain3/domain3.sock;
}
server{
    listen     80;
    server_name ****b.com;
    access_log  logs/web1.access.log  main;
    location / {
        uwsgi_pass  demo1site;
        include     /usr/local/nginx/conf/uwsgi_params;
    }
}

web2.conf

upstream demo2site {
  server unix:///srv/domainB/domainB.sock;
}

server{
  listen     80;
  server_name ****3.com;
  access_log  logs/web2.access.log  main;
  location / {
    uwsgi_pass  demo2site;
    include     /usr/local/nginx/conf/uwsgi_params;
  }  
}


可以看到,两个域名的日志不再混杂了


    配置supervisor控制uwsgi。

pip3 install supervisor

    创建配置文件,只需一个supervisord进程可控制多个django项目

echo_supervisord_conf > demo_supervisor.conf
vim demo_supervisor.conf

主要是命名需要注意,需要保存日志的话,需要提前创建日志目录

[program:web1]
command=uwsgi --ini demo1.ini            
directory=/srv/domain3
stdout_logfile=/srv/domain3/log/s.log      
stderr_logfile=/srv/domain3/log/err.log   

[program:web2]
command=uwsgi --ini demo2.ini        
directory=/srv/domainB            
stdout_logfile=/srv/domainB/log/s.log      
stderr_logfile=/srv/domainB/log/err.log     

 

接下来就可以正常启动、管理项目了

supervisord -c demo_supervisor.conf
supervisorctl -c demo_supervisor.conf

 

为多个网站申请SSL证书

    照例,还是使用python的方法。由于之前我在测试,80端口一直是只对固定IP开放,但申请证书必须全部放开(80,443)

pip install certbot

    standalone,运行独立的Web服务器进行身份验证;-d,DOMAINS,以逗号分隔的域列表,以获取证书;certonly,获取或续订证书

certbot certonly --standalone -d example.com -d www.example.com

    按照要求申请完证书,再来配置nginx配置文件,web1.conf文件如下

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
      '$status $body_bytes_sent "$http_referer" '
      '"$http_user_agent" "$http_x_forwarded_for"';
upstream demo1site {
    server unix:///srv/domain3/domain3.sock;
}
server{
    listen     80;
    server_name ****b.com;
    rewrite ^(.*) https://$host$1 permanent;
}
server {
  listen 443 ssl;
  server_name ****b.com;
  access_log  logs/web1.access.log  main;
  ssl_certificate      /etc/letsencrypt/live/****3.com/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/****3.com/privkey.pem;
  ssl_protocols       TLSv1.3;
  ssl_session_cache    shared:SSL:1m;
  ssl_session_timeout  5m;
location / {
    uwsgi_pass  demo1site;
    include     /usr/local/nginx/conf/uwsgi_params;
   }
}

web2.conf文件最终配置如下

upstream demo2site {
    server unix:///srv/domainB/domainB.sock;
}

server{
    listen     80;
    server_name ****3.com;
    rewrite ^(.*) https://$host$1 permanent;
}

server {
  listen 443 ssl;
  server_name ****3.com;
  access_log  logs/web2.access.log  main;
  ssl_certificate      /etc/letsencrypt/live/****3.com/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/****3.com/privkey.pem;
  ssl_protocols       TLSv1.3;
  ssl_session_cache    shared:SSL:1m;
  ssl_session_timeout  5m;
location / {
    uwsgi_pass  demo2site;
    include     /usr/local/nginx/conf/uwsgi_params;
   }
}

重启nginx


测试完成!

 

参考:

https://stackoverflow.com/questions/29640868/compile-failed-with-error-code-1-in-tmp-pip-build-root-uwsgi