Run Flask app and Gunicorn
flask --app run_server run --debug --host=0.0.0.0 --port=80 gunicorn -w 4 run_server:app -b 0.0.0.0:8080 --reload --access-logfile /var/log/gunicorn/access.log --error-logfile /var/log/gunicorn/error.log --capture-output
For SSL.
gunicorn -w 4 run_server:app -b 0.0.0.0:8080 --reload --access-logfile /var/log/gunicorn/access.log --error-logfile /var/log/gunicorn/error.log --capture-output --keyfile cert/server.key --certfile cert/server.crt
Combined Nginx and Gunicorn.
/etc/nginx/nginx.conf /etc/systemd/systemd/gunicorn.service /etc/systemd/systemd/gunicorn.socket
HTTP request to socket in Almalinux
sudo -u nginx curl --unix-socket /run/gunicorn.sock http
[NOTE]Should restart gunicorn service when modify flask app.
systemctl restart gunicorn.socket
Reference
http://nginx.org/en/docs/beginners_guide.html https://docs.gunicorn.org/en/latest/deploy.html Unix Domain Socket
https://www.freedesktop.org/software/systemd/man/systemd.service.html#Type= https://www.freedesktop.org/software/systemd/man/systemd.unit.html
Nginx Reverse Proxy Hello World
http { server { port 80; root /usr/share/nginx/html; location / { # return index.html in directroy. proxy_pass http://app_server; } } }
/etc/nginx/nginx.conf
# For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; accept_mutex off; # set to 'on' if nginx worker_processes > 1 } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; # 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; upstream app_server { # server unix:/tmp/gunicorn.sock fail_timeout=0; server unix:/run/gunicorn.sock fail_timeout=0; } # 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 / { # } # error_page 404 /404.html; # location = /40x.html { # } # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } # server { # listen 80; # client_max_body_size 4G; # # server_name example.com www.example.com; # # keepalive_timeout 5; # location / { # try_files $uri @proxy_to_app; # } # location @proxy_to_app { # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header Host $http_host; # # we don't want nginx trying to do something clever with # # redirects, we set the Host: header above already. # proxy_redirect off; # proxy_pass http://app_server; # } # error_page 500 502 503 504 /500.html; # location = /500.html { # # } # } server { listen 80; # server_name 127.0.0.1; client_max_body_size 4G; # Default: 1MB. keepalive_timeout 5; # static file path root /usr/share/nginx/html; location / { # checks for static file, if not found proxy to app try_files $uri @proxy_to_app; } location @proxy_to_app { # Add header information to pass to Flask app. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; # we don't want nginx trying to do something clever with # redirects, we set the Host: header above already. proxy_redirect off; proxy_pass http://app_server; } } server { listen 8888; location / { proxy_pass http://localhost:8889; # root /usr/share/nginx/www2/html; } location ~ \.(gif|jpg|png)$ { root /usr/share/nginx/www2/images; } } server { listen 8889; root /usr/share/nginx/www2/up1; location / { } } # Settings for a TLS enabled server. # # server { # listen 443 ssl http2 default_server; # listen [::]:443 ssl http2 default_server; # server_name _; # root /usr/share/nginx/html; # # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 10m; # ssl_ciphers PROFILE=SYSTEM; # ssl_prefer_server_ciphers on; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # location / { # } # # error_page 404 /404.html; # location = /40x.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } }
/etc/systemd/system/gunicorn.service
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] Type=notify User=almalinux Group=almalinux # Generate "gunicorn" folder in "/run/" directory. Delete when stoped. RuntimeDirectory=gunicorn # Generate "gunicorn" folder in "/var/log/" directory. LogsDirectory=gunicorn # Generate "gunicorn" folder in "/etc/" directory. ConfigurationDirectory=gunicorn WorkingDirectory=/home/almalinux/helloworld/gunicorn ExecStart=/home/almalinux/helloworld/gunicorn/venv/bin/gunicorn -w 4 run_server:app -b 0.0.0.0:8080 --reload --access-logfile /var/log/gunicorn/access.log --error-logfile /var/log/gunicorn/error.log --capture-output ExecReload=/bin/kill -s HUP $MAINPID KillMode=mixed TimeoutStopSec=5 PrivateTmp=5 [Install] WantedBy=multi-user.target
/etc/systemd/system/gunicorn.sock
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock # Our service won't need permissions for the socket, since it # inherits the file descriptor by socket activation # only the nginx daemon will need access to the socket SocketUser=nginx # Optionally restrict the socket permissions even more. # SocketMode=600 [Install] WantedBy=sockets.target