Skip to content

Instantly share code, notes, and snippets.

@wonderstory
Created June 1, 2017 06:09
Show Gist options
  • Save wonderstory/60d2538222f7b0e0251f6c47b078a690 to your computer and use it in GitHub Desktop.
Save wonderstory/60d2538222f7b0e0251f6c47b078a690 to your computer and use it in GitHub Desktop.
Flask-uWSGI-nginx on CentOS 7

Small sample of Flask app with uWSGI and nginx on CentOS 7

(Replace example.com, /PATH/TO/CONTENT, APPNAME and USERNAME with yours.)

operations

nginx

$ sudo tee /etc/yum.repos.d/nginx.repo << 'EOF' > /dev/null
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
EOF
$ sudo yum install nginx --enablerepo=nginx

$ sudo firewall-cmd --add-service=http --zone=public --permanent
$ sudo firewall-cmd --add-service=https --zone=public --permanent
$ sudo firewall-cmd --reload

let's encrypt

$ sudo systemctl stop nginx
$ cd /opt
$ sudo git clone https://github.com/certbot/certbot
$ cd certbot
$ sudo ./certbot-auto certonly --standalone -d example.com

python3

$ sudo yum install https://centos7.iuscommunity.org/ius-release.rpm
$ sudo sed -i -e "s/enabled=1/enabled=0/g" /etc/yum.repos.d/ius.repo
$ sudo yum install python36u python36u-devel python36u-pip --enablerepo=ius

uwsgi

$ sudo pip3.6 install uwsgi
Successfully installed uwsgi-2.0.15
$ sudo mkdir -p /etc/uwsgi/vassals
$ sudo nano /etc/uwsgi/vassals/APPNAME_uwsgi.ini
...
$ sudo nano /etc/systemd/system/uwsgi.service
...
$ sudo chown -R nginx:nginx /var/log/uwsgi

venv

$ sudo mkdir -p /var/app/APPNAME
$ sudo chown -R USERNAME:USERNAME /var/app/APPNAME
$ cd /var/app/APPNAME
$ sudo python3.6 -m venv ve
$ source ve/bin/activate
(ve) $ pip install flask
(ve) $ deactivate
$ nano main.py
...
$ sudo chown -R nginx:nginx /var/app/APPNAME

nginx

$ sudo mv /etc/nginx/conf.d/default.conf default.conf.original
$ sudo nano /etc/nginx/conf.d/example.com.conf
...

logrotate

$ sudo nano /etc/logrotate.d/uwsgi
...

run

$ sudo systemctl restart nginx
$ sudo systemctl start uwsgi
$ sudo systemctl enable uwsgi

test

Access https://example.com/app/


(if needed) switch certificate to webroot plugin style and add cron auto renew it

$ sudo mkdir -p /var/www/letsencrypt
$ sudo /opt/certbot/certbot-auto certonly --webroot -w /var/www/letsencrypt -d example.com --agree-tos --force-renewal -n

$ sudo tee /etc/cron.daily/certbot << 'EOF' > /dev/null
#!/bin/sh

/opt/certbot/certbot-auto renew -q --no-self-upgrade --post-hook "systemctl restart nginx"
EOF
$ sudo chmod 755 /etc/cron.daily/certbot
/var/log/uwsgi/emperor.log {
daily
rotate 7
missingok
notifempty
compress
sharedscripts
size 1M
postrotate
touch /var/log/uwsgi/.emperor_logreopen_trigger
endscript
}
/var/log/uwsgi/APPNAME_uwsgi.log {
daily
rotate 7
missingok
notifempty
compress
sharedscripts
size 1M
postrotate
touch /var/app/APPNAME/.logreopen_trigger
endscript
}
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
ssl_protocols TLSv1.2;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
root /PATH/TO/CONTENT;
index index.html;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
location ~ ^/app/(.*)$ {
client_max_body_size 75M;
include uwsgi_params;
uwsgi_pass unix:/var/app/APPNAME/APPNAME_uwsgi.sock;
uwsgi_param SCRIPT_NAME /app;
uwsgi_param PATH_INFO /$1;
}
}
[Unit]
Description=uWSGI
After=syslog.target
[Service]
ExecStart=/usr/bin/uwsgi --master --emperor /etc/uwsgi/vassals --die-on-term --uid nginx --gid nginx --logto /var/log/uwsgi/emperor.log --touch-logreopen /var/log/uwsgi/.emperor_logreopen_trigger
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target
[uwsgi]
base = /var/app/APPNAME
app = main
module = %(app)
home = %(base)/ve
pythonpath = %(base)
socket = %(base)/%n.sock
chmod-socket = 666
callable = app
logto = /var/log/uwsgi/%n.log
touch-logreopen = %(base)/.logreopen_trigger
touch-reload = %(base)/.uwsgi_touch
py-autoreload = 1
max-requests = 1000
harakiri = 60
import os
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello'
if __name__ == '__main__':
app.debug = True
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment