Linux + Nginx + Uwsgi + Django 搭建單服務實現多域名訪問
最近使用Django開發一個小程式和後臺管理系統 ,需要將這兩個不同的專案部署到同一個服務裡面,然後使用不同的域名來訪問不同的專案。Django預設的只支援單服務訪問,要想實現不同域名,需要安裝django的第三方擴充套件包:django-hosts。
本文通過一個簡單的demo來給演示, 看本文的前提是需要對django有一定的認識,對專案環境的搭建以及Nginx有一定的瞭解。
一.搭建環境與專案:
平時習慣使用Anconda來管理Python包,所以本文也使用anconda管理環境,當然大家要是習慣使用virtuallen管理環境也沒有問題。本文主要是演示怎麼完整搭建一個單服務實現多域名訪問的流程,不涉及具體的業務流程。
由於生成django專案需要先下載django包,所以我們先建立一個基本的虛擬環境,然後在虛擬環境中通過具體命令來生成專案檔案。
1、環境搭建:applite_web
conda create --name applite_web
建立完虛擬環境applite_web了,現在需要下載一些依賴包。這裡只需要單獨安裝django與django-hosts即可。
pip install django
pip install django-hosts
pip install uwsgi
2、建立專案:applite_web
django-admin.py startproject applite_web
3、建立app
# 這裡建立4個app.
# app_1、app_2: 是用來匹配applite_web檔案下,hosts.py檔案分發的url
相當django原有的一級url.
# app_1_demo、app_2_demo: 是用來定義自己的API
建立app_1: django manage.py startapp app_1
建立app_2: django manage.py startapp app_2
建立app_1_demo: django manage.py startapp app_1_demo
建立app_2_demo: django manage.py startapp app_2_demo
說明2點:
1)、根據專案的需要,將原來Django專案結構做了調整
2)、至於建立4個app的用法後邊會具體涉及到
下面截圖是建立本文Demo專案結構,當然這也是比較簡單的一個專案結構,實際專案開發中,還需要配置別的引數與檔案。

2. 在applite_web中配置django-hosts
建立好虛擬環境和專案之後,接下來重點就是在django中配置多域名。為了方便起見,本文只演示2個域名,多個域名按照2個域名的方式增加就行。
1、首先在settins.py同級增加一個hosts.py檔案,配置如下:
from django_hosts import patterns, host
host_patterns = patterns(
host(r'app1', 'app_1.urls', name='app1'),
host(r'app2', 'app_2.urls', name='app2'),
)
2、然後在django的settings配置檔案增加3處配置:
在INSTALLED_APPS中增加下面幾個
INSTALLED_APPS = [
"django_hosts",
'app_1',
'app_2',
"app_1_demo",
"app_2_demo",
]
需要在 MIDDLEWARE 的首行和末行增加2行配置
MIDDLEWARE = [
'django_hosts.middleware.HostsRequestMiddleware',
......
'django_hosts.middleware.HostsRequestMiddleware',
]
在ROOT_URLCONF下行增加如下2行引數配置
# 客戶端的請求通過這個配置被轉發到hoss.py檔案的host_patterns中匹配
ROOT_HOSTCONF = 'applite_web.hosts'
# 設定一個預設域名,在沒有匹配所有請求的域名時,預設請求這個域名
DEFAULT_HOST = 'app1'
3. 配置url和view
上邊兩步操作完成,接下來就需要去app資料夾下,編寫對應的url和view。本文是演示2個域名,同時考慮到一般單個專案會有多個模組,所以還需要分別配置兩個url。具體的配置如下:
1、分別在app_1、app_2資料夾下建立urls.py檔案,並且增加對應的url,程式碼如下:
app_1的urls.py檔案如下:
from django.urls import path, include
urlpatterns = [
path("app1/", include("app_1_demo.urls"))
]
app_2的urls.py檔案如下
from django.urls import path, include
urlpatterns = [
path("app2/", include("app_2_demo.urls")),
]
2、然後在app_1_demo、app_2_demo中分別增加對應的url和views函式
在app_1中匹配成功之後,會直接跳轉到app_1_demo的urls,再根據當前的匹配跳轉當前的views函式
1)、首先匹配app_1_demo的urls的路由:
from django.urls import path
from .views import app_1_view
urlpatterns = [
path("", app_1_view),
]
2)、urls匹配成功之後,跳轉這裡的檢視函式,並返回響應
from django.http.response import HttpResponse
# Create your views here.
def app_1_view(request):
return HttpResponse("hello i'm app_1")
同理,app_2匹配成功之後,會直接跳轉到app_2_demo的urls,再根據當前的匹配跳轉當前的views函式
1)、首先匹配app_2_demo的urls的路由,匹配如下:
from django.urls import path, include
from .views import app_2_view
urlpatterns = [
path("", app_2_view)
]
2)、urls匹配成功之後,跳轉這裡的檢視函式,並返回響應
from django.http.response import HttpResponse
# Create your views here.
def app_2_view(request):
return HttpResponse("hello i'm app_2")
4.域名繫結與測試
經過上邊三步的操作,已經完成了一個基本的演示功能。本文目的是通過Nginx負載單服務後,在一個服務裡面來實現不同域名的訪問,所以在配置uwgi和Nginx引數,還需要繫結域名。
1、這裡是在同一個區域網下通過兩臺機器實現使用者的訪問:
訪問機器IP: 192.168.2.17, 部署服務的IP: 192.168.2.200。在實際生產需要購買真實的域名,這裡作為演示,可以通過在本機繫結伺服器的ip的方式來實現對另一臺機器服務的訪問,具體修改如下:
# 需要進入到此檔案中編輯增加下面兩行:sudo vim /etc/hosts
# 這裡我們分別給192.168.2.200繫結app1.cc與app2.cc兩個域名
192.168.2.200 app1.cc
192.168.2.200 app2.cc
2、繫結完之後,然後將本專案放到192.168.2.200機器上,測試當前的服務配置沒有問題。
專案放置路徑為:/home/yxy/payneli/applite_web/
進入app資料夾下,然後執行專案,命令如下:
python manage.py runserver 192.168.2.200:8000
瀏覽器輸入:app1.cc:8000/app1/,如果瀏覽器顯示如下結果,說明專案配置與域名繫結成功

5.uwsgi引數配置與測試
前邊幾步成功之後,接下來就是配置uwsgi的引數。熟悉Python後臺開發的都應該清楚,開發的時候使用的 python manage.py runserver 來執行伺服器,這隻適用開發時的程式碼除錯,而實際專案部署的話,django內建的服務根本無法滿足需求。而Uwsgi作為Python伺服器不僅可以提供穩定的服務,同時還可以提供大的併發量,所以在後臺開發中,用的比較多。
1、在專案資料夾下,建立一個uwsgi資料夾。進入該資料夾,建立uwsgi.ini檔案,裡面的配置引數如下:
[uwsgi]
# 專案目錄
chdir=/home/yxy/payneli/applite_web/app/
# 指定專案的application
wsgi-file=applite_web/wsgi.py
# 指定sock的檔案路徑
socket=/home/yxy/payneli/applite_web/uwsgi/uwsgi.sock
# 程序個數
workers=1
pidfile=/home/yxy/payneli/applite_web/uwsgi/uwsgi.pid
# 指定IP埠
# nginx負載均衡使用socket,uwsgi啟動服務使用http
#socket=192.168.2.200:8000
http=192.168.2.200:8000
# 啟用主程序
master=true
# 自動移除unix Socket和pid檔案當服務停止的時候
vacuum=true
# 序列化接受的內容,如果可能的話
thunder-lock=true
# 啟用執行緒
enable-threads=true
# 設定自中斷時間
harakiri=30
# 設定緩衝
post-buffering=4096
# 設定日誌目錄
daemonize=/home/yxy/payneli/applite_web/logs/uwsgi.log
2、配置完成後,執行下面的命令,啟動服務。
# 在專案路徑下,啟動服務命令如下:
uwsgi --ini ./uwsgi/uwsgi.ini
啟動完成後,uwsgi資料夾裡面就會多出兩個檔案:uwsgi.pid uwsgi.sock

然後檢視當前服務是否啟動成功:
# 命令如下
ps -ef|grep uwsgi
當顯示如下圖所示的時候,說明uwsgi已經將專案啟動成功

3、瀏覽器測試服務是否正常:
在瀏覽為直接輸入:app1.cc:8000/app1/,如果顯示如下,說明uwsgi配置成功

6. Nginx配置與測試
如果前邊5步沒有問題的話,那麼恭喜你,就差最後一步就可以完成本demo的演示了。現在就開始最後一步,配置Nginx引數。
1、首先安裝Nginx,本文對nginx安裝不做講解,畢竟網上教程那麼多,可以找一個好的教程照著操作就可以。小編將Nginx安裝為預設路徑,在:/usr/local/nginx,進入此檔案下,直接命令列啟動。
/usr/local/nginx/sbin/nginx
檢視Nginx是否啟動成功,命令如下:
ps -ef|grep nginx
顯示如下圖,說明Nginx啟動成功

瀏覽器輸入:app1.cc,顯示如下所示,說明Nginx安裝成功

2、檢查Nginx配置沒有問題之後,就是配置多域名了。
註釋掉Nginx原有的配置server

增加如下一行引數,主要是為了方便單獨增加配置app1.cc、與app2.cc兩個域名的檔案

分別在 /usr/nginx/conf/檔案加下,建立一個新的multihosts資料夾,進入該資料夾分別新建 app1.cc.conf、app2.cc.conf檔案,具體的配置引數如下:
app1.cc.conf配置如下:
server{
listen 80; # 預設監聽80埠
server_name app1.cc; # 訪問的域名
#index index.html inex.htm index.php;
#root /data/www/applite_web/;
access_log /usr/local/nginx/logs/app1.log logmain;
rewrite_log on;
#error_page 404 /404.html;
location / { # 通用匹配,任何未匹配到其它location的請求都會匹配到
include uwsgi_params; # uwsgi引數
uwsgi_pass 192.168.2.200:8000; # 負載後臺服務
uwsgi_param UWSGI_CHDIR /home/yxy/payneli/applite_web/app/;
uwsgi_param UWSGI_SCRIPT applite_web.wsgi;
client_max_body_size 35m;
uwsgi_send_timeout 1060;
uwsgi_connect_timeout 1060;
uwsgi_read_timeout 1060;
}
app2.cc.conf配置如下:
server{
listen 80;
server_name app2.cc;
#index index.html inex.htm index.php;
#root /home/yxy/www/applite_web/;
access_log /usr/local/nginx/logs/app2.log logmain;
rewrite_log on;
#error_page 404 /404.html;
location / {
include uwsgi_params;
uwsgi_pass 192.168.2.200:8000;
uwsgi_param UWSGI_CHDIR /home/yxy/payneli/applite_web/app/;
uwsgi_param UWSGI_SCRIPT applite_web.wsgi;
client_max_body_size 35m;
uwsgi_send_timeout 1060;
uwsgi_connect_timeout 1060;
uwsgi_read_timeout 1060;
}
}
3、多域名的引數配置完成,但是此刻不要忘了,當使用Nginx作為負載均衡時候,需要將uwsgi.ini裡面的引數http改為socket具體如下:
# nginx負載均衡使用socket,uwsgi啟動服務使用http
socket=192.168.2.200:8000
# http=192.168.2.200:8000
4、到這裡本文的引數已經配置完成,然後我們需要重新自動Nginx,檢視顯示如上邊啟動效果,說明啟動成功,接下來就是瀏覽器檢測多域名配置是否正確:
分別輸入:app1.cc、app2.cc顯示結果如下,說明多域名已經配置成功


到此為止,單服務實現多域名訪問已經演示完成。當然,本文只是做了一個簡單的demo版本,而實際專案開發的過程中,還需要根據實際需要評估,決定到底是nginx後臺負載多服務,還是nginx負載單服務對映多域名。