Preface
Recently, I have successfully migrated my personal website from Flask to Django. It was about four years ago that I first contacted Django. I remember that routing configuration in Django was done using regularity at that time, but I was particularly tired of it, so I decided to drop the hole.Then at the beginning of this year, I wrote a personal website with Flask. At the beginning, the function was relatively simple. I decided to adopt the routing configuration and deployment rules as they were very convenient.But later, when I wanted to add more and more features, I found it more and more difficult to control. Just recently, I took a little look at the changes in Django over the years. The latest version 2.2 is still good. Routing rules and Flask are consistent, so I'm back in the hole.
At present, the basic functions of my personal website have been migrated.However, during the deployment, I encountered some problems and read some solutions online, either too messy or too old, which I personally feel is no longer applicable.So record my deployment here.
deploy
Much of the web is deployed using UWSGI, but I personally prefer Gunicorn, so here's just a record of how Django + Gunicorn + Nginx is deployed on Ubuntu.
Step One
Upload site source to target server
Since my source code is hosted on Github, I can simply execute the following command to clone my site source code to the server.
git clone https://github.com/your-name/repo-name.git # Enter Project Directory cd repo-name # Create and activate virtual environments python3 -m virtualenv venv source venv/bin/activate # Installation Project Dependency pip install -r requirements.txt
The dependent packages currently used on my website are as follows:
autopep8 Django django-bootstrap4 django-ckeditor gunicorn Markdown Pillow python-slugify requests
There is a pit to note here. If you are using awesome-slugify, try python-slugify, because awesome-slugify may not be installed properly on your server. BUG can refer to: Clashes with python-slugify package.
Step 2
Modify project-related configurations and collect static resources
Since I need to deploy my Web site to a production environment, I need to turn off Django's debugging mode and modify the static resource-related configuration as follows:
- settings.py
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY') DEBUG = os.environ.get('DJANGO_DEBUG', False) TEMPLATE_DEBUG = os.environ.get('DJANGO_TEMPLATE_DEBUG', False) ALLOWED_HOSTS = ["*"] 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', ], }, }, ] STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ] MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Then execute the following command for static resource collection:
python manage.py collectstatic
After that, I need to create a configuration for the Gunicorn process as follows:
- gunicorn.conf.py
# install # sudo pip3 install gunicorn import sys import os import logging import logging.handlers from logging.handlers import WatchedFileHandler import multiprocessing BASE_DIR = '/home/hippie/hippiezhou.fun/src' sys.path.append(BASE_DIR) LOG_DIR = os.path.join(BASE_DIR, 'log') if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) # Bound ip and port bind = "0.0.0.0:8000" # Run in the background as a daemon daemon = True # Maximum number of pending connections, 64-2048 backlog = 512 # overtime timeout = 30 # Debugging Status debug = False # The destination working directory gunicorn will switch to chdir = BASE_DIR # Work process type (default is sync mode, also includes eventlet, gevent, or tornado, gthread, gaiohttp) worker_class = 'sync' # Number of worker processes workers = multiprocessing.cpu_count() # Specify the number of threads opened per worker process threads = multiprocessing.cpu_count() * 2 # Log level, which refers to the level of error logs (debug, info, warning, error, critical) that cannot be set for accessing logs loglevel = 'info' # Log format access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"' # Each of these options has the following meanings: ''' h remote address l '-' u currently '-', may be user name in future releases t date of the request r status line (e.g. ``GET / HTTP/1.1``) s status b response length or '-' f referer a user agent T request time in seconds D request time in microseconds L request time in decimal seconds p process ID ''' # Access log files accesslog = os.path.join(LOG_DIR, 'gunicorn_access.log') # Error log file errorlog = os.path.join(LOG_DIR, 'gunicorn_error.log') # pid file pidfile = os.path.join(LOG_DIR, 'gunicorn_error.pid') # Access log file,'-'for standard output accesslog = "-" # Error log file,'-'for standard output errorlog = "-" # Process name proc_name = 'hippiezhou_fun.pid' # More configurations please: gunicorn -h to view
You can then launch our website by:
# Startup mode (first you need to switch to the project root directory, which is in the same directory as manage.py): gunicorn -c gunicorn.conf.py website.wsgi:application # or gunicorn website.wsgi:application -b 0.0.0.0:8000 -w 4 -k gthread # or gunicorn website.wsgi:application -b 0.0.0.0:8000 -w 4 -k gthread --thread 40 --max-requests 4096 --max-requests-jitter 512 # View process ps aux | grep gunicorn
Step Three
Configure Nginx
Through the first two steps, we can successfully run our website, but at present it can only be accessed internally, so we need to use Nginx as a reverse proxy for external access.
Perform the following commands for installation and configuration
sudo apt-get install nginx sudo service nginx start # Backup Default Configuration sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak # Start Vim to modify our site configuration sudo vim /etc/nginx/sites-available/default
The example configuration is as follows:
server{ ... server_name hippiezhou.fun *.hippiezhou.fun; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ... location / { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. # try_files $uri $uri/ =404; proxy_pass http://127.0.0.1:8000; #Here you want to be consistent with your gunicore's ip and port proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /static { alias /root/hippiezhou.fun/src/staticfiles; # This time you need to configure the absolute path of the static resource corresponding to your site } location /media { alias /root/hipiezhou.fun/src/media; # If your site has upload capabilities, you need to configure the node and point to the target path } ... }
Once the configuration is complete, do the following to get our site up and running
# If the site does not start executing the command gunicorn -c gunicorn.conf.py website.wsgi:application sudo nginx -t sudo service nginx restart
If nothing unexpected happens, the site should be accessible. If static resources are still inaccessible, open the developer's tool to see what went wrong.
- If it's a 404 problem, make sure your settings configuration is consistent with the one listed above.
- If this is a 403 problem, it should be that Nginx does not have access to the static resource you specified. You need to modify the user type of Nginx and execute the following command in person
sudo vim /etc/nginx/nginx.conf
Modify the value after user to root and restart Nginx.
Finally, without much discussion on how to configure HTTPS, you can directly list the example scripts:
sudo apt-get update sudo apt-get install software-properties-common sudo add-apt-repository universe sudo add-apt-repository ppa:certbot/certbot sudo apt-get update sudo apt-get install certbot python-certbot-nginx sudo certbot --nginx # sudo certbot renew --dry-run sudo ufw allow https sudo systemctl restart nginx
summary
In the process of deployment, in fact, the most common problem encountered is that static resources can not be problem, but many articles on the Internet are different, and some of them are written incorrectly.So here's a summary.Fortunately, everything went well.It's like filling a hole four years ago.
Finally, for an advertisement, welcome to my personal website: hippiezhou.fun