Try   HackMD

Django網站系統部署

Reference Website:

  1. How To Deploy Django on Ubuntu 18.04 using Apache and MySQL
  2. How to use Django with Apache and mod_wsgi
  3. [Django] Window Apache 架站
  4. 利用 Mod_wsgi 在 Apache 上部屬 Django
  5. Django + Apache 部署
  6. Django 部署(Apache)

環境要求與基礎確認 (USE terminal)

  • OS:Linux - ubuntu 18.04
  • Framework - Django
    • Django專案:stat01
  • Database - MySQLDB
  • 伺服軟體 - Apache
  • IP address - 140.136.153.182 (實體IP)
    ​​​​sudo apt install net-tools
    ​​​​ifconfig
    
  • python 確認
    ​​​​python
    

108扶秀作品集

  • OS:Linux - Debian 10
  • Framework - Django
    • Django專案:Portfolio_Voting
  • Database - MariaDB
  • 伺服軟體 - Apache
  • IP address - 140.136.202.234 (實體IP)
  • Python, Git
  • ssh
    ​​​​white504@white504-System-Product-Name:~$ ssh user@140.136.202.234
    ​​​​user@140.136.202.234's password: 
    ​​​​Linux hecct 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2+deb10u1 (2020-06-07) x86_64
    
    ​​​​The programs included with the Debian GNU/Linux system are free software;
    ​​​​the exact distribution terms for each program are described in the
    ​​​​individual files in /usr/share/doc/*/copyright.
    
    ​​​​Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    ​​​​permitted by applicable law.
    ​​​​Last login: Sat Jul 11 19:49:50 2020 from 140.136.153.167
    
    ​​​​user@hecct:~$ su - root
    ​​​​Password: 
    ​​​​root@hecct:~#
    
  • Can not use apt install ...?
    • Question
      • 一開始在設定的時候只有設學校的 DNS ,所以根本沒辦法解析 debian 的 domain 啊…
    • Solve
      • 解決辦法就直接到 /etc/resolv.conf 加上

        ​​​​​​​​​​​​nameserver 127.0.0.1
        ​​​​​​​​​​​​nameserver 8.8.8.8
        

        就搞定了啊= =
        到底為啥會搞那麼久啊…


  • 先安裝Django和MySQLDB,接著安裝並設定Apache,最後才能從外網連到網站。
  • MySQLDB的部分:
    • 安裝mysql-server, mysql-client,然後再把Django與MySQLDB做連結,這樣資料才會寫進MySQLDB裡。

Step 1: Python安裝與虛擬環境建立 + Django安裝

  • 安裝 Python3 & pip3

    ​​sudo apt install python3-pip
    
    • 安裝虛擬環境套件

      ​​​​sudo su
      ​​​​sudo pip3 install virtualenv
      
    • 顯示目前所安裝的套件

      ​​​​pip3 freeze
      ​​​​pip freeze
      
  • 移至根目錄建立site_test資料夾,並建立與啟用虛擬環境

    ​​cd /
    ​​mkdir site_test
    ​​cd site_test/
    ​​
    ​​virtualenv venv -p python3
    ​​source venv/bin/activate
    
  • 安裝虛擬環境&Django套件

    ​​pip install django
    
  • 備註:
    • 完整解除安裝 + 刪除其配置的文件

      ​​​​sudo apt autoremove --purge python3
      
    • 安裝 get-pip.py

      ​​​​curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
      ​​​​python3 get-pip.py --user --force-reinstall
      
    • 安裝 gnome-terminal

      ​​​​sudo apt install --reinstall gnome-terminal
      
    • 安裝 文字編輯器 geany

      ​​​​sudo apt install geany
      
    • set mysql password policy

      ​​​​set global validate_password_policy=LOW;
      

Step 2: 建立Django專案 + 修改settings.py

  • 準備已做好的Django projectstat01 (github範例檔)

    ​​sudo apt install git
    ​​git clone https://github.com/stat-website/stat_begin.git
    
  • 建立Django projectstat01及其網頁內容

    ​​django-admin startproject stat01
    ​​cp -r /home/testchia/stat_begin/stat01 .
    
  • 查詢IP並修改settings.py

    • 查詢IP

      ​​​​ifconfig
      
    • 修改settings.py

      ​​​​cd stat01/stat01
      ​​​​nano settings.py	-> ALLOWED_HOSTS = ['140.136.153.182']
      
  • 練習:
    • 建立Django project

      ​​​​django-admin startproject tutorial
      
    • 建立Django app

      ​​​​cd tutorial
      ​​​​python manage.py startapp app
      
    • 下指令刪除整個Django project

      ​​​​rm -r tutorial
      

Step 3: MySQLDB安裝與設定

How To Install MariaDB on Debian 10

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
MariaDB connected with Django (Bible Note)
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • 使用Terminal安裝MySQLDB

    ​​sudo apt update
    ​​sudo apt upgrade
    ​​sudo apt install mysql-server	
    ​​sudo mysql_secure_installation
    
    ​​sudo apt install mysql-client
    ​​sudo apt install python3-dev libmysqlclient-dev
    

    Mariadb

    sudo apt update
    sudo apt upgrade
    sudo apt install mariadb-server mariadb-client
    sudo mysql_secure_installation
    
  • 確認 mysql / mariadb 有開啟

    ​​systemctl status mysql.service
    
  • 進入 MySQL/ mariadb 建立Database,以供Django使用

    ​​mysql -u root -p
    ​​
    ​​CREATE USER <testchia_test>@localhost IDENTIFIED BY '<password>';
    ​​CREATE DATABASE <db_demo> CHARACTER SET UTF8;
    ​​GRANT ALL PRIVILEGES ON <db_demo>.* TO <testchia_test>@localhost;
    ​​SHOW DATABASES;
    
  • 安裝mysqlclient套件

    ​​pip install mysqlclient
    

    Mariadb does not need!

  • migrate + check Database tables

    ​​python manage.py migrate
    
    ​​mysql -u root -p
    ​​SHOW DATABASES;
    ​​USE db_demo;
    ​​SHOW TABLES;
    ​​
    ​​exit
    
  • runserver

    ​​python manage.py runserver 140.136.153.182:80
    ​​
    ​​python manage.py runserver 0.0.0.0:8000
    
  • Note:
    • Only, Mariadb 需要安裝pymysql套件

      • pip3 install pymysql

  • Createsuperuser

    ​​python manage.py createsuperuser
    
    • 打開瀏覽器

      ​​​​140.136.153.182/admin
      

Step 4: Apache2

  • 安裝Apache2

    ​​sudo apt install apache2 libapache2-mod-wsgi-py3
    
    • 開啟瀏覽器 140.136.153.182
  • 修改Apache2設定 (建立stat01.conf)

    ​​cd /etc/apache2/
    ​​cd sites-available/
    ​​
    ​​cp 000-default.conf stat01.conf	-> copy as stat01.conf
    ​​sudo nano stat01.conf
    
    • stat01.conf

      ​​​​<VirtualHost *:80>
      ​ServerName 140.136.153.182
      
      ​ServerAdmin webmaster@localhost
      ​DocumentRoot /site_test
      
      ​​​​ErrorLog /site_test/error.log
      ​​​​CustomLog /site_test/access.log combined
      
      
      ​​​​<Directory /site_test/stat01/stat01>
      ​​​​        <Files wsgi.py>
      ​​​​                Require all granted
      ​​​​                Require ip 127.0.0.1
      ​​​​        </Files>
      ​​​​</Directory>
      
      
      ​WSGIDaemonProcess site_test python-path=/site_test/stat01 python-home=/site_test/venv
      ​​​​WSGIProcessGroup site_test
      ​​​​WSGIScriptAlias / /site_test/stat01/stat01/wsgi.py
      
      ​​​​</VirtualHost>
      
  • 檢查語法

    ​​​​sudo apachectl configtest
    

Apache啟動報錯


Step 5: 套用stat01.conf設定 + 重新啟動Apache2

  • 關閉預設000-default.conf、開啟stat01.conf

    ​​a2dissite 000-default.conf
    ​​a2ensite stat01.conf
    
  • 載入設定 + 重新啟動Apache2

    ​​systemctl reload apache2
    ​​systemctl restart apache2
    
    ​​/etc/init.d/apache2 restart
    
  • 查看Apache2狀態

    ​​systemctl status apache2.service
    

Step 6: Apache2的靜態檔案路徑設定

  • 建立一個新資料夾,修改settings.py

    ​​mkdir /site_test/stat01/static/all_static
    ​​nano settings.py
    
    • 修改settings.py

      ​​​​STATIC_URL = '/static/'
      ​​​​STATICFILES_DIRS=[
      ​​​​        os.path.join(BASE_DIR,'static'),
      ​​​​]
      
      ​​​​STATIC_ROOT = '/site_test/stat01/static/all_static'
      
  • 下指令將所有靜態檔案蒐集至此資料夾之下(admin interface & static)

    ​​python manage.py collectstatic
    
  • 修改stat01.conf

    ​​nano /etc/apache2/sites-available/stat01.conf
    
    ​​Alias /static /site_test/stat01/static/all_static
    ​  
    ​  <Directory /site_test/stat01/static/all_static>
    ​  	Require all granted
    ​  </Directory>
    
  • 重新啟動Apache2

    systemctl restart apache2

  • Note:
    • settings.py

      ​​​​DEBUG = FALSE
      

完整程式碼

settings.py

# -- coding:UTF-8 -- """ Django settings for about_01 project. Generated by 'django-admin startproject' using Django 2.1. For more information on this file, see https://docs.djangoproject.com/en/2.1/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/2.1/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'v4q50ygn$$t!oa#)+0(58326ai4t8mr=wmc(+o+!q9!+pvvt)8' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = ['140.136.153.182'] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', '_student', '_teacher', '_about', '_contact', '_research', '_class', '_join', '_sitemap', '_download', '_bonus', '_association', '_news', '_sitemember', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'stat01.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR,'templates')], #新增 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'stat01.wsgi.application' # Database # https://docs.djangoproject.com/en/2.1/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'db_demo', 'USER': 'testchia_test', 'PASSWORD': 'testchia', 'HOST': 'localhost', 'PORT': '', } } # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/2.1/topics/i18n/ LANGUAGE_CODE = 'zh-Hant' #新增 TIME_ZONE = 'Asia/Taipei' #新增 USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.1/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS=[ #新增 os.path.join(BASE_DIR,'static'), #注意,BASE_DIR 不用加引號 ] STATIC_ROOT = '/site_test/stat01/static/all_static'

stat01.conf

<VirtualHost *:80>
	ServerName 140.136.153.182

	ServerAdmin webmaster@localhost
	DocumentRoot /site_test

	# For most configuration files from conf-available/, which are
	# enabled or disabled at a global level, it is possible to
	# include a line for only one particular virtual host. For example the
	# following line enables the CGI configuration for this host only
	# after it has been globally disabled with "a2disconf".
	#Include conf-available/serve-cgi-bin.conf

        ErrorLog /site_test/error.log
        CustomLog /site_test/access.log combined


        <Directory /site_test/stat01/stat01>
                <Files wsgi.py>
                        Require all granted
			Require ip 127.0.0.1
                </Files>
        </Directory>


	Alias /static /site_test/stat01/static/all_static
	
	<Directory /site_test/stat01/static/all_static>
		Require all granted
	</Directory>


	WSGIDaemonProcess site_test python-path=/site_test/stat01 python-home=/site_test/venv
        WSGIProcessGroup site_test
        WSGIScriptAlias / /site_test/stat01/stat01/wsgi.py

</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

__init__.py (Project Level)

#import pymysql #pymysql.install_as_MySQLdb()

108扶秀作品集 hecct.fju.edu.tw

/etc/apache2/site-available/hecct.conf

<VirtualHost *:80>
        #ServerName www.hecct.fju.edu.tw
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/FJU_Portfolio_Voting/Portfolio_Voting

        ErrorLog /var/www/error.log
        CustomLog /var/www/access.log combined

        Alias /static/ /var/www/FJU_Portfolio_Voting/Portfolio_Voting/staticfiles/
        <Directory /var/www/FJU_Portfolio_Voting/Portfolio_Voting/staticfiles>
                Require all granted
        </Directory>

        #Alias /media/ /var/www/FJU_Portfolio_Voting/Portfolio_Voting/media/
        #<Directory /var/www/FJU_Portfolio_Voting/Portfolio_Voting/media>
        #       Require all granted
        #</Directory>

        <Directory /var/www/FJU_Portfolio_Voting/Portfolio_Voting/Portfolio_Voting/>
                <Files wsgi.py>
                        Require all granted
                </Files>
        </Directory>

        WSGIDaemonProcess Portfolio_Voting python-path=/var/www/FJU_Portfolio_Voting/Portfolio_Votin$
        WSGIProcessGroup Portfolio_Voting
        WSGIScriptAlias / /var/www/FJU_Portfolio_Voting/Portfolio_Voting/Portfolio_Voting/wsgi.py
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

settings.py

ALLOWED_HOSTS = ['140.136.202.234', 'hecct.fju.edu.tw', '*'] ... DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'hecctdb', 'USER': 'admin', 'PASSWORD': 'zj6vu.4yji4qup3ru6', 'HOST': 'localhost', 'PORT': '', } } ... STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # will build a file 'media' in same level path as manag$ # LOGIN_REDIRECT_URL = '/' LOGOUT_REDIRECT_URL = '/'

__init__.py (Project Level)

pip3 install pymysql

import pymysql pymysql.version_info = (1, 3, 13, "final", 0) pymysql.install_as_MySQLdb()