HelloGitHub- dream chasers

The sample code covered in this article has been synchronously updated to the HelloGithub-Team repository

The basic functionality of the blog has been developed, and although there are still many areas to improve, we still hope to deploy the blog on the server soon, so that others can access it through the Internet. As for areas that need to be improved, you can iterate and improve little by little after deployment. Now let’s deploy the blog to the server!

↓↓↓ Video is here ↓↓↓

The author personally recorded the real machine environment demonstration deployment process, or success you hit me!

B station demo (ali cloud CentOS 7 system) watch the address: www.bilibili.com/video/av680…

Note: Each step in this article is verified in a real-world environment. Unless you know what you are doing, it is recommended that you follow the instructions of the tutorial strictly at each step to ensure that you can successfully deploy.

Preparing for deployment

We will use the popular Nginx + Gunicorn method to deploy django-developed blogs to your own server, allowing others to access your blog through a domain name. Aside from what Nginx and Gunicorn are, you’ll know what they do and how to use them after reading this tutorial.

In order to deploy our blog, two conditions need to be met:

  1. It is best to have a server that can be accessed from the Internet (if not, you can build a virtual machine on your own computer and access it through a virtual IP address).
  2. It is best to have a domain name (if not, you can only access it using IP and cannot turn on HTTPS).

Configuring the Server

This tutorial uses a Windows 10 local environment and a CentOS 7 (64-bit) server environment. If your environment is different from mine (like Ubuntu) and some commands don’t work, just convert those commands to your environment, and focus on understanding what each step does so you can successfully deploy in any environment, rather than just copying and pasting commands.

Remotely log in to the server

The server is usually located in the cloud. You need to use a remote login tool to log in to the server. I use Xshell, Windows baidu Xshell download installation, software for schools and personal users is free.

How to log in to the server remotely here is not redundant, I believe you can refer to some tutorials on the web will be able to log in smoothly. If you use Xshell like I do, here is a detailed tutorial on how to use Xshell to remotely connect to a Linux server.

Create a superuser

We have successfully connected to the remote server. If it is a brand new server, we would normally log in as root. It is not safe to deploy code under root, so it is best to create a new user (skip this step if you are already logged in as a non-root user). The following list of commands will create a new user with super privileges (replace yangxg with the username you want, I’ll use my name pinyin yangxg here) :

Create a new user by running this command as user root. Yangxg is the username
# Because my name is Yang Xueguang, so MY username is Yangxg
# Choose a username you like, not necessarily the same as mine
root@server:~# adduser yangxg

Set password for new user
# Note that there will be no character display when typing the password. Do not assume that the keyboard is broken
root@server:~# passwd yangxg

Add the newly created user to the supergroup
root@server:~# usermod -aG wheel yangxg

# Switch to the new user created
root@server:~# su - yangxg

# switch successfully, @ symbol before the new user name instead of root
yangxg@server:$
Copy the code

The new user was created and switched successfully. If it is a new server, it is best to update the system first, to avoid the installation of software because the version is too old. Run the following two commands:

yangxg@server:$ sudo yum update
yangxg@server:$ sudo yum upgrade
Copy the code

Update the SQLite3

For convenience, we use the SQLite3 database. Django 2.2 requires SQLite3 to be at least 3.8.3. CentOS 7 has a lower version than Django 2.2 requires. So let’s start by updating the version of SQLite3.

Pay attention to

It is possible that you are using a server system distribution SQLite3 that is higher than 3.8.3, so skip this step. How do I view the version of SQLite3? Run sqlite3 –version

Go to the official download address of SQLite and check out the latest release, which will be 3.29.0 by the time this tutorial is complete. Find the source package, copy the download link, and download it to the server using the wget command (I usually put the source in the ~/ SRC directory).

Create SRC directory and go to this directory
yangxg@server:$ mkdir -p ~/src
yangxg@server:$ cd ~/src

# Download the sqlite3 source code and unzip it
yangxg@server:$ wget https://sqlite.org/2019/sqlite-autoconf-3290000.tar.gz
yangxg@server:$ tar zxvf sqlite-autoconf-3290000.tar.gz
yangxg@server:$ cd sqlite-autoconf-3290000
yangxg@server:$ ./configure
yangxg@server:$ make
yangxg@server:$ sudo make install
Copy the code

Tip:

If the wget command does not exist, use sudo yum install -y wget.

Now that SQLite3 has been updated, Python3 is installed.

Install Python3 and Pipenv

CentOS 7 comes with a Python release of 2.7, so Python3 needs to be installed. Python 3.6.4 is installed for compatibility.

First install possible dependencies:

yangxg@server:$ sudo yum install -y openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel
Copy the code

Then download the Python 3.6.4 source and unzip it:

yangxg@server:$ cd~ / SRC yangxg @ server: $wget yangxg @ https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tgz server: $tar ZXVF. - Python - 3.6.4 radar echoes captured. TGZCopy the code

Finally compile and install:

yangxg@server:$ cdPython - 3.6.4 radar echoes captured yangxg @ server: $. / configure LD_RUN_PATH = / usr /local/lib LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include"
yangxg@server:$ make LD_RUN_PATH=/usr/local/lib
yangxg@server:$ sudo make install
Copy the code

Note that Python relies on the SQLite3 library when installing Python, so LD_RUN_PATH specifies the dependent search directory when configuring (since we updated SQLite3 earlier, Specify the dependency search directory to ensure that the new SQLite3 dependency library is used), and the other two parameters work similarly.

Then run python3.6 -v and pip3.6 -v to test the installation. The output version number indicates that the installation is successful.

With PIP, you can install Pipenv:

yangxg@server:$sudo pip3.6 install pipenvCopy the code

Tip:

Pip3.6 is installed in /usr/local/bin/bin of the current user. Use the pip3.6 install pipenv –users command to also install pipenv in the bin directory of the current user.

The deployment code

The next step is to get ready to deploy the code to get our blog application running on the service, exactly the same as it would have been if it had been developed locally. But to deploy the application to the server, we first need to configure the project a little bit. Open settings.py, find the ALLOWED_HOSTS, and change it to:

blogproject/settings.py

ALLOWED_HOSTS = ['127.0.0.1'.'localhost '.'.zmrenwu.com']
Copy the code

After specifying the value of ALLOWED_HOSTS, Django will only allow access to our application through the specified domain name, such as 127.0.0.1, Localhost, zmrenwu.com and any of its subdomains (a dot before the domain name indicates that access to the subdomain name is allowed) (that is, the value of Host in the header of the HTTP message must be the domain name specified above. Usually, when you enter the domain name in the browser to access the website, The value of Host is set to the domain name of the web site, thus avoiding HTTP Host header attacks.

Django projects have static files such as CSS and JavaScript. To make it easier for Nginx to handle requests for these static files, we collect all the static files in a single directory, which is usually located at the root of a Django project. And name it static. To accomplish these tasks, you need to do some necessary configuration in the project configuration file:

blogproject/settings.py

# Other configuration...

STATIC_URL = '/static/'
Add the following configuration
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
Copy the code

STATIC_ROOT specifies the static file collection path, in this case BASE_DIR (the project root directory, defined at the beginning of the settings.py file).

The key now is to get the code out to the server, where git is used. Install git first:

yangxg@server:$ sudo  yum install -y git
Copy the code

Upload the code to a hosting platform like GitHub so we can easily pull the code to the server. Git and GitHub are already familiar to you, so I won’t go over the process here. If you do not know how to use the words you can baidu related tutorials. Do not upload database files!

I usually like to put the application code in the ~/apps/ directory. Let’s first set up the server file structure to store the application code and other related files:

Create apps directory in user directory and enter
yangxg@server:$ mkdir -p ~/apps
yangxg@server:$ cd ~/apps

# Pull blog code
yangxg@server:$ git clone https://github.com/HelloGitHub-Team/HelloDjango-blog-tutorial.git
Copy the code

Then go to the project root directory and install the project dependencies:

yangxg@server:$ cd ~/apps/HelloDjango-blog-tutorial

yangxg@server:$ pipenv install --deploy --ignore-pipfile
Copy the code

With the –deploy parameter specified here, Pipenv will only install dependencies specified under [Packages] in Pipfile. Because we are now deploying in an online environment, we do not need dependencies that are only for the development environment.

–ignore-pipfile will cause Pipenv to install project dependencies from the pipfile. lock file. Pipfile.lock records the exact information about project dependencies, and reading the dependency information from here ensures that the dependencies are inadvertently modified or corrupted to cause unexpected problems in the runtime due to dependency packages.

Pipenv will automatically create the virtual environment for us, and then install the project dependencies into the virtual environment.

Then create a database:

yangxg@server:$ pipenv run python manage.py migrate
Copy the code

Start the development server:

yangxg@server:$pipenv run python manage.py runserver 0.0.0.0:8000Copy the code

Here we specify the IP and port on which the server will run when we start the development server, which will allow access to our blog through port 8000 of the public IP.

Access IP address :8000, you can see that the access is successful (the IP address is the public IP address of your server).

Using Gunicorn

The official Django documentation emphasizes that development servers started with RunServer are for development testing only and are not recommended for production environments. So we used the popular Gunicorn to start servers that could be used in an online environment.

First go to the project root directory and install Gunicorn:

yangxg@server:$ pipenv install gunicorn
Copy the code

The Pipfile and pipfile. lock files in the gunicorn server will be updated, so don’t forget to synchronize the changes locally.

Server submits code
yangxg@server:$ git add Pipfile Pipfile.lock
yangxg@server:$ git commit -m "add gunicorn dependency"
yangxg@server:$ git push

# local pull code
git pull
Copy the code

Back to the online server, in the project root directory, execute the following command to start the service:

yangxg@server:$pipenv run gunicorn blogproject.wsgi -w 2 -k gthread-b 0.0.0.0:8000Copy the code

To explain what each parameter means.

‘-w 2 means to start two workers for processing requests (a worker can be understood as a process), usually set the number of workers to 2-4 times the number of CPU cores.

-k gthread specifies how each worker processes requests. According to our practice, the asynchronous mode designated as Gthread can obtain relatively high performance, so we adopt this mode.

-b 0.0.0.0:8000 Binds the service to port 8000 to access applications using the public IP address and port 8000.

Access IP :8000 (IP is your server’s public IP address), the application successfully access, but we see that the style is completely out of order. Don’t worry, it’s not a bug! Previously, we used django’s built-in development server, which automatically handled static style files for us, but Gunicorn didn’t do that for us. Since handling static files is not Gunicorn’s area of expertise, it should be left to a more specialized service application, such as Nginx.

Start the Nginx server

Nginx (Engine X) is a high-performance HTTP and reverse proxy Web server. It has many functions. Here we mainly use it to process static files and reverse proxy requests for non-static files to Gunicorn.

When we visit a blog post details page, the server receives two requests:

  • Displays detailed information about the article, which is usually stored in a database and therefore requires a database call to retrieve the data.
  • Static files such as images, CSS, and JS are stored in a folder on the server.

In the case of the former request, the blog post data needs to be retrieved from the database with Django. Nginx can’t handle it, so it forwards the request to the Django application running on the Gunicorn service for Django to handle. For the latter type of static file request, simply go to the folder where the static file is located and get it. Nginx handles it for you without troubling Django.

Getting static files with Django can be time-consuming, but Nginx handles it efficiently, which is why we use Nginx.

Install Nginx first:

yangxg@server:$ sudo yum install epel-release -y
yangxg@server:$ sudo yum install nginx -y
Copy the code

Run the following command to start the Nginx service:

yangxg@server:$ sudo systemctl start nginx
Copy the code

Enter the IP address in the browser (port 80 is the default if no port is entered, and Nginx listens for requests on port 80 by default). If you see the Nginx welcome screen, Nginx has started successfully.

Configure Nginx

The Nginx configuration is in the /etc/nginx/nginx.conf file. You can open this file to see what it contains. Here are some key configurations:

user nobody nobody; . http { # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { } } }Copy the code

The first is the user configuration, which specifies the user and group to which the Nginx process is running (the first and second parameters, respectively). To prevent possible permissions issues, we will change to the current system user (my username is yangxg, which belongs to the group yangxg, remember to change to the user and group running on your own server. Remember to save the contents of the file after modification) :

user yangxg yangxg;
Copy the code

Then there is a server module under the HTTP configuration. The server module is used to configure a virtual service that listens on specified ports and domain names. You can configure multiple servers so that multiple virtual services are launched to listen on different ports, or on the same port but with different domain names, so that you can deploy multiple Web applications on the same server.

Include includes the configuration file in the specified path, which facilitates modular management of configuration. For example, we can put the configuration of different Web applications in /etc/nginx/conf.d/. Then nginx will include all the.conf files in this directory in the configuration of nginx.conf. Instead of having to heap all the configuration into nginx.conf, the configuration file becomes bloated.

Let’s configure the blog application. As mentioned above, for modular management, we will write the configuration to /etc/nginx/conf.d/. Start by creating a new configuration file in the conf.d directory on the server, which I’ll call hellodjango-blog-tutorial.conf. Write the following configuration:

server {
    charset utf-8;
    listen 80;
    server_name hellodjango-blog-tutorial-demo.zmrenwu.com;

    location /static {
        alias /home/yangxg/apps/HelloDjango-blog-tutorial/static;
    }

    location / {
        proxy_set_header Host $host;
        proxy_passhttp://127.0.0.1:8000; }}Copy the code

First we configure a virtual service, encoded in UTF-8, listening on port 80.

The domain name of the service is hellodjango-blog-tutorial-demo.zmrenwu.com, so requests from this domain are handled by the service.

All URL matching /static requests are handled by Nginx, and alias specifies the directory where static files are stored so that Nginx can find the requested file and return it to the client.

Other requests are forwarded to the application running on port 8000 of the native machine, where Gunicorn will be launched to handle requests forwarded by Nginx.

Restart nginx for the configuration to take effect:

yangxg@server:$ sudo systemctl restart nginx
Copy the code

Disable the DEBUG mode to collect static files

Django sets the DEBUG option in settings.py to True for easy debugging. This allows you to see the DEBUG information in the settings.py file if the application fails. So we set the DEBUG option to False, turn off DEBUG mode, and locally set the DEBUG in settings.py to:

DEBUG=False
Copy the code

The online server updates the latest code and then runs the command to collect the static files to the previously configured STATIC_ROOT directory:

yangxg@server:$ pipenv run python manage.py collectstatic
Copy the code

Then use Gunicorn to start the service.

yangxg@server:$pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 127.0.0.1:8000Copy the code

Now, visit the configured domain hellodjango-blog-tutorial-demo.zmrenwu.com (change to your own domain configured in Nginx), and see the blog successfully deployed!

Manage the Gunicorn process

Now Gunicorn is manually started by us, and once we exit the shell, the server is shut down and the blog cannot be accessed. Even if you start Gunicorn in the background, if the server crashes and restarts one day, you have to log in to start the server again. For this reason, the Supervisor manages the Gunicorn process so that when the server restarts or the Gunicorn process crashes unexpectedly, the Supervisor automatically restarts Gunicorn for us.

Press Ctrl + C to stop the Gunicorn service process that you just started.

Install the Supervisor first. Note that piP2 is used with the system, since The Supervisor does not support Python3 as of the writing of this tutorial, but this does not affect use.

yangxg@server:$ pip install supervisor
Copy the code

For convenience, I usually set up the following directory structure (located in the ~/etc directory) to manage Supervisor related files:

├── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ──log└ ─ ─ supervisord. ConfCopy the code

The supervisor. conf is the Supervior configuration file that will contain the configuration for conf.d. The var directory is used to store some files that change frequently, such as socket files and PID files. The log directory is used to store log files.

First, set up the directory structure above:

yangxg@server:$ mkdir -p ~/etc/supervisor/conf.d
yangxg@server:$ mkdir -p ~/etc/supervisor/var/log
Copy the code

Then go to the ~/etc directory to generate the Supervisor configuration file:

yangxg@server:$ cd ~/etc
yangxg@server:$ echo_supervisord_conf > supervisord.conf
Copy the code

Modify supervisor.conf so that some of the files produced by the Supervisor process are generated in the directory we created above, instead of where they are specified by default.

First go to the [unix_http_server] section and change the file setting to the following:

[unix_http_server]
file=/home/yangxg/etc/supervisor/var/supervisor.sock
Copy the code

The socket file is generated in the ~/etc/supervisor/var/ directory. Note that supervisor does not support expanding ~ to the user home directory, so specify an absolute path.

It’s similar to changing the path of the logFile and pidFile files under the [container] plate, and changing the user to the system user, so that processes started by the Supervisor will run as the system user, avoiding any permissions issues:

logfile=/home/yangxg/etc/supervisor/var/log/supervisord.log
pidfile=/home/yangxg/etc/supervisor/var/supervisord.pid
user=yangxg
Copy the code

It is also seen in the [supervisorctl] section:

serverurl=unix:///home/yangxg/etc/supervisor/var/supervisor.sock
Copy the code

Will include sections, / home/yangxg/etc/supervisor/conf. D/all directory with the ini at the end of the file contents included in the configuration, so easy to configure the modular management, and before the Nginx configuration file handling is similar.

files = /home/yangxg/etc/supervisor/conf.d/*.ini
Copy the code

Then we go to conf.d and create a new configuration for our blog application:

[program:hellodjango-blog-tutorial]
command=pipenv run gunicorn blogproject.wsgi -w 2 -k gthread -b 127.0.0.1:8000
directory=/home/yangxg/apps/HelloDjango-blog-tutorial
autostart=true
autorestart=unexpected
user=yangxg
stdout_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stdout.log
stderr_logfile=/home/yangxg/etc/supervisor/var/log/hellodjango-blog-tutorial-stderr.log
Copy the code

Here are the meanings of each configuration:

[program:hellodjango-blog-tutorial] specifies the process to run the application, named hellodjango-blog-tutorial.

  • Command indicates the command that is executed when the process is started.

  • Directory Specifies the directory where the command is executed.

  • Autostart Automatically starts processes with Supervisor.

  • The autorestart process is restarted when it unexpectedly exits.

  • User Indicates the user who runs the process to prevent permission problems.

  • Stdout_logfile, stderr_logfile Log output file.

Start the Supervisor

yangxg@server:$ supervisord -c ~/etc/supervisord.conf
Copy the code

-c Specifies the configuration file it is handling when it is launched.

Is displayed on the supervisorCTL process management console.

yangxg@server:$ supervisorctl -c ~/etc/supervisord.conf
Copy the code

Run the update command to update the configuration file and start the application.

Enter the domain name in the browser, and you can see that the service has started normally.

CDN to speed up the loading of Bootstrap and jQuery

Our project uses Bootstrap and jQuery, which we loaded locally. If the server performance is poor, loading takes a long time and the site opens unbearably fast. We use CDN to speed up loading. Specifically, replace the loading tags of several static files in base.html:

base.html

- <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
- <script src="{% static 'blog/js/jquery - 2.1.3. Min. Js' %}"></script>
- <script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
+ <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
+ <script src="https://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script>
+ <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
Copy the code

After modifying the code locally, sync the code to the online server and restart the hellodjango-blog-tutorial application by executing the following command:

yangxg@server:$ supervisorctl -c ~/etc/supervisord.conf restart hellodjango-blog-tutorial 
Copy the code

This website access speed will be greatly enhanced!

conclusion

Deployment step many and complex, because each environment is different, so the deployment is the most easy to get wrong step, must make clear the role of every step, so that when they have a problem, can be targeted to solve, if you only know blindly copy and paste commands, and don’t know what they’re doing, so once the wrong will do.

Deployment process automation

We ran a dozen commands and manually entered N characters throughout the deployment. It would be cumbersome to remotely connect to the server to execute these commands every time the code was updated. The following tutorials will cover automating the entire deployment process using Fabric. Once the deployment script is written, you can easily automate the entire deployment by executing a single command.

“Explain Open Source Project series” — let the people who are interested in open source projects not be afraid, let the initiator of open source projects not be alone. Follow along as you discover the joys of programming, use, and how easy it is to get involved in open source projects. Welcome to leave a message to contact us, join us, let more people fall in love with open source, contribute to open source ~