Skip to content

Commit f8fd12b

Browse files
committed
Initial commit
0 parents  commit f8fd12b

File tree

8 files changed

+234
-0
lines changed

8 files changed

+234
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app/venv

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) [2018] [source-nerd]
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# PYTHON FLASK WITH NGINX & UWSGI
2+
3+
## CONTENTS
4+
5+
1. app Folder
6+
2. uwsgi.ini
7+
3. nginx_config
8+
4. production_flask.service
9+
10+
## USAGE
11+
12+
1. app Folder - It contains you complete app and directories. Do initialize it as a virtual environment and install `requirements.txt` included in that folder. (Hold on !!) We will be going through it in some time
13+
2. uwsgi.ini - UWSGI server configuration. Edit/Replace the following places:
14+
* my_app_folder: Replace `PROJECT_FOLDER_HERE` With your Project app Path
15+
* my_user: Replace `MY_USERNAME_HERE` With your UserName; You can get your username using command `whoami`
16+
3. nginx_config - Contains the main nginx configuration. Edit/Replace the following to make it work properly:
17+
* uwsgi_pass: Replace `PROJECT_FOLDER_HERE` With your Project Path
18+
* [OPTIONAL] listen: Port on which you want nginx to Listen
19+
* [OPTIONAL] server_name: Currently its `0.0.0.0` . You can change it as per your needs.
20+
4. production_flask.service - A Systemd service file to ensure that the server restarts on failure and can be set to auto-start in case of server restart. Edit/Replace the following terms:
21+
* Replace `USER_NAME_HERE` with your user-name.
22+
* Replace `PROJECT_FOLDER_HERE` with your project app directory
23+
* Replace `uwsgi.ini_PATH_HERE` with `uwsgi.ini` path
24+
25+
## PREREQUISITES
26+
27+
1. Clone this repository.
28+
2. A Stable Debian based Linux O.S, preferrably Ubuntu with `sudo` privileges configured. I have tried it on Ubuntu 18.04 and it worked flawlessly.
29+
3. We will me utilizing Virtual Env Wrapper for complete Flask Project.
30+
4. Before proceeding any further, Install the following packages:
31+
32+
``` PYTHON
33+
sudo apt-get update
34+
sudo apt-get install python3 python3-pip
35+
sudo apt-get install systemd nginx
36+
sudo pip3 install virtualenv
37+
```
38+
39+
5. Initializing Project Virtual Environment:
40+
41+
```PYTHON
42+
cd PROJECT/APP_FOLDER
43+
virtualenv -p python3 venv
44+
source venv/bin/activate
45+
pip3 install -r requirements.txt
46+
```
47+
6. Now, as this project is configured with a simple Hello World Application inside `app.py`, we will be using it for deployment. You can also have your complete project inside the app folder with an `app.py` file
48+
49+
## INSTALLATION INSTRUCTIONS
50+
51+
Now comes the main dreaded and & feared (kiddin!) Installation part.
52+
Considering you have installed all the above steps successfully, will start with Nginx.
53+
54+
1. You will need to place your `nginx_config` in `/etc/nginx/sites-available/nginx_config`. Then, to enable this nginx configuration, we will have to link it to the nginx sites-enabled directory using this command:
55+
```SHELL
56+
sudo ln -s /etc/nginx/sites-available/nginx_config /etc/nginx/sites-enabled
57+
```
58+
The above command will create a sym-link for `nginx_config`
59+
60+
2. Restart Nginx:
61+
```SHELL
62+
sudo service nginx restart
63+
```
64+
3. Before starting up the main service, let make a folder for logs; the configuration for which is defined in `uwsgi.ini`
65+
```SHELL
66+
sudo mkdir -p /var/log/uwsgi
67+
sudo chown -R thetechfreak:thetechfreak /var/log/uwsgi
68+
```
69+
Instead of `thetechfreak` use your username.
70+
4. Now, we will have to configure systemd service & for that we place `production_flask.service` in `/etc/systemd/system/production_flask.service` and then restart and enable the service to auto start after reboot.
71+
```SHELL
72+
sudo systemctl start production_flask.service
73+
sudo systemctl enable production_flask.service
74+
```
75+
At this point, our service should successfully start and incase of any updates you can just restart the service using:
76+
```SHELL
77+
sudo systemctl restart production_flask.service
78+
```
79+
80+
> ### After this step, your server should be up and running
81+
82+
## LOGGING & MONITORING
83+
84+
In order to check the logs, you can navigate to the logs directors `/var/log/uwsgi/`
85+
86+
Monitoring the service is also very easy as you justneed to go inside your `PROJECT_DIR` and run the following command:
87+
88+
```PYTHON
89+
uwsgitop stats.production_flask.sock
90+
```
91+
92+
OR
93+
94+
If you want to monitor the logs of the application itself, you can make use of `journalctl`: Note: These logs are same as the one which are stared in `/var/log/uwsgi/`; So, unless you really want to have a real time log on your system, it's not required:
95+
96+
```PYTHON
97+
sudo journalctl -u production_flask.service -f
98+
```
99+
100+
## Serving Static Files Using Nginx
101+
102+
If your application requires static files to be served, you can add the following rule inside `nginx_config` file:
103+
104+
```CONFIG
105+
location /static {
106+
root APP_DIR;
107+
}
108+
```
109+
110+
Replace `APP_DIR` with your application directory and as a result, all your static files located at `APP_DIR/static` will be served by nginx
111+
112+
## FINAL THOUGHTS
113+
114+
These are my final thoughts and some notes which are worth noting.
115+
116+
1. UWSGI is configured in `lazy-apps` mode which is responsible for loading the application one time per worker. You can read more about it [here](http://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html)
117+
2. Only Basic configuration of nginx is used; however it is sufficient for most of the use cases. But still, if you want to tune it further you can read up [here](https://docs.nginx.com/nginx/admin-guide/load-balancer/)
118+
3. If your app requires some `parameters` to be passed, you can make use of [CONFIGPARSERS](https://docs.python.org/3/library/configparser.html) but DO-NOT pass it via command line as uWSGI is the one responsible for invoking the app.
119+
4. In this app, `Socket permission` is given to everyone. You can adjust it as per your needs, but make sure that nginx and uWSGI can still talk to each other
120+
5. If something goes wrong, the first place to check is the `log` files. By default, nginx writes error message to the file `/var/log/nginx/errors.log`
121+
122+
Contributions are very welcome.
123+
Do make PULL requests if you want to change anything, or post an ISSUE if you encounter any bugs.

app/app.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from flask import Flask
2+
3+
app = Flask(__name__)
4+
5+
6+
@app.route("/")
7+
def hello():
8+
return "Hello World!"
9+
10+
11+
if __name__ == "__main__":
12+
app.run(host='0.0.0.0', port=4444, debug=True)

app/requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Flask==1.0.2
2+
uwsgi
3+
uwsgitop==0.10
4+
virtualenv==16.0.0

nginx_config

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
server {
2+
listen 80;
3+
# change this to your server name or IP
4+
server_name 0.0.0.0;
5+
6+
location / {
7+
include uwsgi_params;
8+
# change this to the location of the uWSGI socket file (set in uwsgi.ini)
9+
uwsgi_pass unix:PROJECT_FOLDER_HERE/production_flask.sock;
10+
}
11+
}

production_flask.service

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Unit]
2+
Description=uWSGI instance to serve production_ml service
3+
4+
[Service]
5+
User=USER_NAME_HERE
6+
WorkingDirectory=PROJECT_FOLDER_HERE
7+
Environment="PATH=PROJECT_FOLDER_HERE/venv/bin"
8+
ExecStart=PROJECT_FOLDER_HERE/venv/bin/uwsgi --ini uwsgi.ini_PATH_HERE/uwsgi.ini
9+
Restart=on-failure
10+
11+
[Install]
12+
WantedBy=multi-user.target

uwsgi.ini

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[uwsgi]
2+
# placeholders that you have to change
3+
my_app_folder = PROJECT_FOLDER_HERE
4+
my_user = MY_USERNAME_HERE
5+
6+
socket = %(my_app_folder)/production_flask.sock
7+
chdir = %(my_app_folder)
8+
file = app.py
9+
callable = app
10+
11+
# environment variables
12+
env = CUDA_VISIBLE_DEVICES=-1
13+
env = KERAS_BACKEND=theano
14+
env = PYTHONPATH=%(my_app_folder):$PYTHONPATH
15+
16+
master = true
17+
processes = 5
18+
# allows nginx (and all users) to read and write on this socket
19+
chmod-socket = 666
20+
# remove the socket when the process stops
21+
vacuum = true
22+
23+
# loads your application one time per worker
24+
# will very probably consume more memory,
25+
# but will run in a more consistent and clean environment.
26+
lazy-apps = true
27+
28+
uid = %(my_user)
29+
gid = %(my_user)
30+
31+
# uWSGI will kill the process instead of reloading it
32+
die-on-term = true
33+
# socket file for getting stats about the workers
34+
stats = %(my_app_folder)/stats.production_flask.sock
35+
36+
# Scaling the server with the Cheaper subsystem
37+
38+
# set cheaper algorithm to use, if not set default will be used
39+
cheaper-algo = spare
40+
# minimum number of workers to keep at all times
41+
cheaper = 5
42+
# number of workers to spawn at startup
43+
cheaper-initial = 5
44+
# maximum number of workers that can be spawned
45+
workers = 50
46+
# how many workers should be spawned at a time
47+
cheaper-step = 3
48+
49+
#location of log files
50+
logto = /var/log/uwsgi/%n.log

0 commit comments

Comments
 (0)