The original address

I’ve been learning Python recently, I’ve implemented a personal blog application in Flask, and I want to deploy it to a server. As a novice, I stumbled all the way and finally got it basically done. The information on the Internet is not very friendly to novices, they are fragmented, so I sorted it out, on the one hand, as my own record, convenient for future reference, on the other hand, I also hope to help novices like me.

The premise

  1. Have a server (otherwise make wool), purchase can refer to high quality foreign VPS recommendation

  2. There are personal domain names (of course, you can use IP access directly, but it’s a bit weird isn’t it? To buy a domain name, go to GoDaddy

1. Install git

You can build your own Git server on Github or Bitbucket, but I don’t think it’s necessary. Bitbucket is a free private repository

sudo yum install git
Copy the code

The following is no different from our local development. Configure SSH key, clone code, do not expand, recommend to put the project directory in /home/www/

2. Installation of Mysql

Add MySQL YUM source

$wget 'https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm'
$sudo rpm -Uvh mysql57-community-release-el7- 11.noarch.rpm
$yum repolist all | grep mysql

mysql-connectors-community/x86_64 MySQL Connectors Community                  36
mysql-tools-community/x86_64      MySQL Tools Community                       47
mysql57-community/x86_64          MySQL 5.7 Community Server                 187

Copy the code

Install the latest version

$sudo yum install mysql-community-server
Copy the code

Start the MySQL service

$sudo service mysqld start 

$sudo systemctl start mysqld #CentOS 7

$sudo systemctl status mysqld

● mysqld.service - MySQL Community Server

   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)

   Active: active (running) since Sat 2017-05-27 12:56:26 CST; 15s ago

  Process: 2482 ExecStartPost=/usr/bin/mysql-systemd-start post (code=exited, status=0/SUCCESS)

  Process: 2421 ExecStartPre=/usr/bin/mysql-systemd-start pre (code=exited, status=0/SUCCESS)

 Main PID: 2481 (mysqld_safe)

   CGroup: /system.slice/mysqld.service

├ ─ 2481 / bin/sh/usr/bin/mysqld_safe - basedir = / usr

├ ─ 2147 / usr/sbin/mysql.txt -- conf =/ usr/sbin/mysql.txt -- conf =/ usr/sbin/mysql.txt -- conf =/ usr/sbin/mysql.txt -- conf =/ usr/sbin/mysql.txt

Copy the code

It indicates that the system is running

Change the password

$ mysql -uroot -p 

Copy the code

Run the grep “temporary password” /var/log/mysqld.log command to query the default password of the root user

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword';

Copy the code

Modify the code

Set the default encoding in /etc/my.cnf

[client]

default-character-set = utf8

[mysqld]

default-storage-engine = INNODB

character-set-server = utf8

collation-server = utf8_general_ci # case insensitive

collation-server = utf8_bin # case sensitive

collation-server = utf8_unicode_ci # more accurate than UTf8_general_ci

Copy the code

Creating a database

mysql> CREATE DATABASE <datebasename> CHARACTER SET utf8;

Copy the code

3. Install PYTHon3 PIp3

CentOS 7 has Python 2 installed by default. If you need to use Python 3, you can manually download the Python source code and compile it.

Install Python 3

sudo mkdir /usr/local/python3 Create the installation directory
$ wget --no-check-certificate https://www.python.org/ftp/python/3.62./Python3.62..tgz Download the Python source file
# Note: when wget gets HTTPS, add --no-check-certifica
$ tar -xzvf Python3.62..tgz Unzip the package
$ cd Python3.62. Go to the unzip directory
sudo ./configure --prefix=/usr/local/python3 # specify the directory to create
sudo make
sudo make install # build install
Copy the code

Configure: error: no acceptable C compiler found in $PATH configure: error: no acceptable C compiler found in $PATH

Sudo yum install gcc-C ++ sudo yum install gcc-C ++

Configure the coexistence of two versions

Create python3 soft link:

$ sudo ln -s /usr/local/python3/bin/python3 /usr/bin/python3
Copy the code

This allows you to use Python 2 through the Python command, python3 to use Python 3.

Install the PIP

$ sudo yum -y install epel-release Install the EPEL extension source first
$ sudo yum -y install python-pip # python installed - PIP
$ sudo yum clean all # to clear the cache
Copy the code

It seems that piP2 can only be installed in this way. To install PIP in Python 3, you can install it from the following source code.

# Download source code
$ wget --no-check-certificate https://github.com/pypa/pip/archive/9.01..tar.gz

$ tar -zvxf 9.01..tar.gz    Unzip the file

$ cd pip9.01.

$ python3 setup.py install # Install using Python 3
Copy the code

Create a link:

$ sudo ln -s /usr/local/python3/bin/pip /usr/bin/pip3
Copy the code

Upgrade PIP

$ pip install --upgrade pip
Copy the code

4. Install gunicorn

Gunicorn (Unicorn) is a highly efficient Python WSGI Server, which is usually used to run WSGI Applications (our own authoring specification that follows WSGI Application) or WSGI Framework (such as Django,Paster), which is equivalent to Tomcat in Java. WSGI is one such protocol: it is an interface between Python programs and user requests. The WSGI server’s job is to accept and analyze the user’s request, call the appropriate Python object to process the request, and return the corresponding result. To put it simply, Gunicorn encapsulates the underlying implementation of HTTP. We start the service through Gunicorn, and user requests and services are transmitted through Gunicorn

Creating a Virtual Environment

cd /home/www/blog
mkdir venv
python3 -m venv venv
Copy the code

Activating the virtual environment:

source venv/bin/activate
Copy the code

Then install dependencies from the requirements.txt file:

pip3 install -r requirements.txt
Copy the code

Install the gunicorn

pip3 install gunicorn
Copy the code

Create a wsgi.py file in the project root directory

from app import create_app

application = create_app('production')

if __name__ == '__main__':
    application.run()
Copy the code

No longer start the service through manage.py, which is only used at development time

Start the service:

gunicorn -w 4 -b 127.0. 01.:8000 wsgi:application
Copy the code

5. Install Nginx

Nginx is a high-performance Web server. It is usually used as a reverse proxy server on the front end. The so-called “reverse” and “forward” are just English translation. Proxy service, in short, a request is sent from the LAN through a proxy server and then to a server on the Internet. The proxy for this process is forward proxy. If a request comes in from the Internet, it goes to a proxy server and is forwarded by the proxy server to the target server on the LAN, the proxy server is the reverse proxy (as opposed to forward).

Forward proxy: {client — Proxy server} — server

Reverse proxy: Client — {proxy server — > server}

{} indicates LAN

Nginx can do both forward and reverse.

$ yum -y install nginx
Copy the code

Start the nginx service

$ service nginx start
Copy the code

Stop the nginx service

$ service nginx stop
Copy the code

Restart the nginx service

$ service nginx restart
Copy the code

Smooth restart

Nginx configuration changes can be reloaded without first closing and then opening

$ nginx -s reload
Copy the code

After startup, enter the IP address of the server in the browser and you can see it

Yum install nginx

Add the configuration

The nginx configuration file is /etc/nginx/nginx.conf

server {
        listen 80;
        server_name adisonhyh.com;

        location / {
                proxy_pass http://127.0. 01.:8000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}Copy the code
  • Listen for the HTTP default port number 80
  • Server_name: indicates the domain name of the personal website
  • Proxy the request to port 8000 of the machine (the port specified by gunicorn to start the service) and copy the remaining proxy_set_header

Gunicorn and Nginx:

Gunicorn can be serviced separately, but production environments generally do not. Firstly, static resources (JSCSSIMG) will occupy a lot of request resources, while Gunicorn should pay more attention to the request and processing of actual business rather than waste resources on static resource requests. In addition, running Gunicorn alone does not allow multiple processes and ports to load balance.

Nginx can handle all static file requests as the front-end server. In this case, Gunicorn is the back-end server. Nginx will forward dynamic requests to the back-end server, so we can have multiple Gunicorn processes. Then let NGINx load balance forwarding requests to multiple Gunicorn processes to improve server processing efficiency and capacity. Finally, nginx can also configure a lot of security-related, authentication-related processing, so that your website can focus more on business writing, leaving some non-business things like forwarding rules to Nginx.

After configuration, open the local browser, enter the domain name, should be able to access.

6.supervisor

Supervisor is a good choice if you need the process to run all the time and automatically restart it if it is interrupted for any reason. The Supervisor manages the processes by starting them as children of the Supervisor by fork/exec, so all we need to do is add the path of the executable that will manage the processes to the Supervisor configuration file. If the supervisor process is abnormal, the parent process can obtain information about the abnormal supervisor process. By setting AutoStart =true in the configuration file, the parent process can automatically restart the abnormal supervisor process.

The installation supervisor

$ pip install supervisor
$ echo_supervisord_conf > supervisor.conf   Generate the Supervisor default configuration file
$ vim supervisor.conf                       Modify the Supervisor configuration file to add the Gunicorn process management
Copy the code

Add to the bottom of the blog supervisor.conf configuration file (note that my working path is WWW /home/blog/)

[the program: blog] command = / home/WWW/blog/venv/bin/gunicorn w4 - b0.0.0.0:8000 wsgi: application; Supervisor start command directory=/home/ WWW /blog; Project folder path startSecs =0; Start time stopWaitSecs =0; Autostart =false; Autorestart =false; Whether automatic restart stdout_logfile = / home/WWW/blog/logs/gunicorn log; The log log stderr_logfile = / home/WWW/blog/logs/gunicorn err; The error logCopy the code

Start Gunicorn with Supervsior

$ sudo supervisord -c supervisor.conf  
$ sudo supervisorctl start blog
Copy the code

To access the website, enter the configured address in the address bar of the browser.

7. fabric

As a final step, we use Fabric for remote operation and deployment. Fabric is a Python tool similar to Makefiles, but capable of executing commands on remote servers.

Install the fabric

pip install fabric
Copy the code

Create a new fabfile.py file in the blog directory

import os
from fabric.api import local, env, run, cd, sudo, prefix, settings, execute, task, put
from fabric.contrib.files import exists
from contextlib import contextmanager

env.hosts = ['204.152.201.69']
env.user = 'root'
env.password = '* * * *'# your password
env.group = "root"

DEPLOY_DIR = '/home/www/blog'
VENV_DIR = os.path.join(DEPLOY_DIR, 'venv')
VENV_PATH = os.path.join(VENV_DIR, 'bin/activate')


@contextmanager
def source_virtualenv(a):
    with prefix("source {}".format(VENV_PATH)):
        yield


def update(a):
    with cd('/home/www/blog/'):
        sudo('git pull')


def restart(a):
    with cd(DEPLOY_DIR):
        if not exists(VENV_DIR):
            run("virtualenv {}".format(VENV_DIR))
        with settings(warn_only=True) :with source_virtualenv():
                run("pip install -r {}/requirements.txt".format(DEPLOY_DIR))
                with settings(warn_only=True):
                    stop_result = sudo("supervisorctl -c {}/supervisor.conf stop all".format(DEPLOY_DIR))
                    if not stop_result.failed:
                        kill_result = sudo("pkill supervisor")
                        if not kill_result:
                            sudo("supervisord -c {}/supervisor.conf".format(DEPLOY_DIR))
                            sudo("supervisorctl -c {}/supervisor.conf reload".format(DEPLOY_DIR))
                            sudo("supervisorctl -c {}/supervisor.conf status".format(DEPLOY_DIR))
                            sudo("supervisorctl -c {}/supervisor.conf start all".format(DEPLOY_DIR))


@task
def deploy(a):
    execute(update)
    execute(restart)

Copy the code

Now, if the code is updated, you can perform remote deployment directly locally

fab deploy
Copy the code