{"id":161,"date":"2018-03-03T18:48:25","date_gmt":"2018-03-03T10:48:25","guid":{"rendered":"https:\/\/www.techcoil.com\/blog\/?p=161"},"modified":"2018-03-04T21:35:17","modified_gmt":"2018-03-04T13:35:17","slug":"how-to-deploy-python-3-flask-application-on-raspberry-pi-3-with-raspbian-stretch-lite-nginx-supervisor-virtualenv-and-gunicorn","status":"publish","type":"post","link":"https:\/\/www.techcoil.com\/blog\/how-to-deploy-python-3-flask-application-on-raspberry-pi-3-with-raspbian-stretch-lite-nginx-supervisor-virtualenv-and-gunicorn\/","title":{"rendered":"How to deploy Python 3 Flask application on Raspberry Pi 3 with Raspbian Stretch Lite, Nginx, Supervisor, Virtualenv and Gunicorn"},"content":{"rendered":"<p><a href=\"https:\/\/www.amazon.com\/Raspberry-Pi-RASPBERRYPI3-MODB-1GB-Model-Motherboard\/dp\/B01CD5VC92\/ref=as_li_ss_tl?ie=UTF8&qid=1519745335&sr=8-3&keywords=Raspberry+Pi+3+board&linkCode=ll1&tag=clivsperswebs-20&linkId=349641857f08826cc78099b4402f5f70\" rel=\"noopener\" target=\"_blank\">Raspberry Pi 3 Model B boards<\/a> make good <a href=\"https:\/\/www.techcoil.com\/shop\/for\/gifts-for-programmers\" rel=\"noopener\" target=\"_blank\">gifts for programmers<\/a> and if someone had gifted you with one, you may want to use it as a control center for interacting with various IoT sensors and devices at home.<\/p>\n<p>In such a situation, you may want to build a Python 3 <a href=\"http:\/\/flask.pocoo.org\/\" rel=\"noopener\" target=\"_blank\">Flask<\/a> application to present the web interface for accessing the control center.<\/p>\n<p>After you had built that Python 3 Flask application, the next step will be to deploy it on your Raspberry Pi 3 for serving HTTP requests. <\/p>\n<p>This post discusses how you can deploy a Python 3 Flask application on Raspberry Pi 3 with Raspbian Stretch Lite, <a href=\"http:\/\/nginx.org\/\">Nginx<\/a>, <a href=\"https:\/\/virtualenv.pypa.io\" rel=\"noopener\" target=\"_blank\">Virtualenv<\/a> and <a href=\"http:\/\/gunicorn.org\/\" rel=\"noopener\" target=\"_blank\">Gunicorn<\/a>.<\/p>\n<h2>Creating a simple Python 3 Flask application as a proof of concept<\/h2>\n<p>Let us create a simple Python 3 Flask application to demonstrate the deployment of Python 3 Flask application on our Raspberry Pi 3 with Raspbian Stretch Lite, Nginx, Supervisor, Virtualenv and Gunicorn.<\/p>\n<h3>Project structure of our simple Python 3 Flask application<\/h3>\n<p>The simple application consists of a directory with the following contents:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nsimpleapp\r\n|--requirements.txt\r\n|--start.sh\r\n|--src\r\n   |--__init__.py\r\n|--static\r\n<\/pre>\n<h3>Specifying Flask as a dependency in <code>requirements.txt<\/code><\/h3>\n<p>The <code>requirements.txt<\/code> file is for specifying the Python 3 dependencies that our Python 3 Flask application is going to need. Since this is a minimalistic application, the <code>requirements.txt<\/code> contains only the following line:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nFlask==0.12.2\r\n<\/pre>\n<h3>Creating start.sh for Supervisor to start the Python 3 Flask application<\/h3>\n<p>The shell script is intended for the Supervisor daemon to start our Python 3 Flask application. The shell script contains the following content:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nsource simpleappenv\/bin\/activate\r\ngunicorn --workers 5 --bind unix:simpleapp.sock -m 007 src:app\r\ndeactivate\r\n<\/pre>\n<p>The <code>simpleappenv<\/code> directory contains a virtual environment that we will created later with <a href=\"https:\/\/virtualenv.pypa.io\" rel=\"noopener\" target=\"_blank\"><code>virtualenv<\/code><\/a>. In this shell script, we first get into the virtual environment by sourcing the <code>activate<\/code> script that resides in <code>simpleappenv\/bin<\/code> directory. <\/p>\n<p>Once the virtual environment is activated, we will then use the <code>gunicorn<\/code> binary to run our Python 3 Flask application. The command tells Gunicorn to use 5 workers for handling HTTP requests directed at the Python 3 Flask application. Gunicorn will listen for HTTP requests via the <code>simpleapp.sock<\/code> unix socket. Only processes running the same user as this start.sh script can communicate with Gunicorn through the <code>simpleapp.sock<\/code> unix socket. Gunicorn will also look into the <code>src<\/code> package to find an <code>app<\/code> variable to realise the Python 3 Flask application.<\/p>\n<p>We will install a version of gunicorn that can run Python 3 applications into the virtual environment later. <\/p>\n<p>The <code>deactivate<\/code> command will be run when the Python 3 Flask application got terminated by whatever reason. In such a case, the executor of the shell script will get out of the virtual environment.<\/p>\n<h3>Building the Python 3 Flask application inside <code>src\/__init__.py<\/code><\/h3>\n<p>The <code>src\/__init__.py<\/code> Python script will be run when the <code>src<\/code> directory is being read by Python. The <code>src\/__init__.py<\/code> file contains the following Python code:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom flask import Flask\r\napp = Flask(__name__)\r\n \r\n@app.route('\/')\r\ndef hello_world():\r\n    return 'Hello there, welcome to our app!'\r\n<\/pre>\n<p>In this file, we import Flask, construct a Flask object and set it to the <code>app<\/code> variable. We then decorate a function to return the message <strong>Hello there, welcome to our app!<\/strong> for HTTP requests directed at the root URL.<\/p>\n<h3>Using the <code>static<\/code> directory to serve as the root directory for Nginx<\/h3>\n<p>The <code>static<\/code> directory is meant to serve as the root directory for Nginx. We will use this directory to keep images, CSS, JavaScript and other kinds of static files.<\/p>\n<h2>Setting up Raspbian Stretch Lite on Raspberry Pi 3 to run Python 3 applications<\/h2>\n<p>As a first step to the deployment of your Python 3 Flask application, <a href=\"https:\/\/www.techcoil.com\/blog\/how-to-setup-raspbian-stretch-lite-on-raspberry-pi-3-to-run-python-3-applications\/\" rel=\"noopener\" target=\"_blank\">follow this tutorial to setup Raspbian Stretch Lite on Raspberry Pi 3 to run Python 3 applications<\/a>. After doing so, you will get your Raspberry Pi 3 running the Raspbian Stretch Lite operating system with the following software pieces:<\/p>\n<ul>\n<li>SSH server which enables you to configure Raspbian Stretch Lite remotely.<\/li>\n<li>Python 3 for running your Python 3 Flask application.<\/li>\n<li>Python 3 package manager (pip3) for installing the dependencies for your Python 3 Flask application.<\/li>\n<li>Virtualenv for you to create an isolated environment for running your Python 3 Flask application.<\/li>\n<\/ul>\n<h2>Getting our Python 3 Flask application project files into our Raspberry Pi 3 via SSH<\/h2>\n<p>Assuming that our Raspberry Pi 3 is accessible via the IP address <strong>192.168.1.109<\/strong> and we are at the directory that contains the <code>simpleapp<\/code> directory, we will run the following shell command to perform the copy over to the home directory of the <code>pi<\/code> user: <\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nscp -r simpleapp pi@192.168.1.109:~\r\n<\/pre>\n<p>After the files are transferred over to your Raspberry Pi 3, run the following command to get into your Raspbian Stretch Lite:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nssh pi@192.168.1.109\r\n<\/pre>\n<p>Once you log into your Raspbian Stretch Lite via SSH, move the project files to the <code>\/var\/flaskapp<\/code> directory by running the following command:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo mkdir \/var\/flaskapp\r\nsudo mv ~\/simpleapp \/var\/flaskapp\/\r\n<\/pre>\n<p>Once you had moved the project files, make the <code>\/var\/flaskapp\/simpleapp\/start.sh<\/code> executable by the owner:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo chmod 744 \/var\/flaskapp\/simpleapp\/start.sh\r\n<\/pre>\n<h2>Installing Nginx on Raspbian Stretch Lite<\/h2>\n<p>Nginx runs very well on Raspberry Pi 3 and serves as a solid <a href=\"https:\/\/www.techcoil.com\/blog\/the-reverse-proxy-server\/\" rel=\"noopener\" target=\"_blank\">reverse proxy server<\/a> for proxying HTTP traffic to different upstream servers. With Nginx in the same box as our Python 3 Flask application, we have the flexibility to complement the Python 3 Flask application with applications written in another language in the future.<\/p>\n<p>To install Nginx, run the following commands:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo apt-get update\r\nsudo apt-get install nginx -y\r\n<\/pre>\n<p>After the installation had completed, verify the installation by running the following command:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo systemctl status nginx\r\n<\/pre>\n<p>This command should give you output similar to the following if Nginx had installed successfully:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n\u25cf nginx.service - A high performance web server and a reverse proxy server\r\n   Loaded: loaded (\/lib\/systemd\/system\/nginx.service; enabled; vendor preset: enabled)\r\n   Active: active (running) since Sat 2018-03-03 13:35:15 +08; 42s ago\r\n     Docs: man:nginx(8)\r\n  Process: 17632 ExecStart=\/usr\/sbin\/nginx -g daemon on; master_process on; (code=exited, status=0\/SUCCESS)\r\n  Process: 17629 ExecStartPre=\/usr\/sbin\/nginx -t -q -g daemon on; master_process on; (code=exited, status=0\/SUCCESS)\r\n Main PID: 17633 (nginx)\r\n   CGroup: \/system.slice\/nginx.service\r\n           \u251c\u250017633 nginx: master process \/usr\/sbin\/nginx -g daemon on; master_process on;\r\n           \u251c\u250017634 nginx: worker process\r\n           \u251c\u250017635 nginx: worker process\r\n           \u251c\u250017636 nginx: worker process\r\n           \u2514\u250017637 nginx: worker process\r\n\r\nMar 03 13:35:15 raspberrypi systemd&#x5B;1]: Starting A high performance web server and a reverse proxy server...\r\nMar 03 13:35:15 raspberrypi systemd&#x5B;1]: Started A high performance web server and a reverse proxy server.\r\n<\/pre>\n<h2>Installing Supervisor on Raspbian Stretch Lite<\/h2>\n<p>Next up is the installation of Supervisor. Supervisor is a convenient tool for running applications as a server daemon. We will use Supervisor to run Gunicorn in an isolated environment.<\/p>\n<p>To install Supervisor, run the following command:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo apt-get install supervisor -y\r\n<\/pre>\n<p>Once the command completes, run the following command to verify your installation:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo systemctl status supervisor\r\n<\/pre>\n<p>You should see output similar to the following if Supervisor had been installed successfully:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n\u25cf supervisor.service - Supervisor process control system for UNIX\r\n   Loaded: loaded (\/lib\/systemd\/system\/supervisor.service; enabled; vendor preset: enabled)\r\n   Active: active (running) since Sat 2018-03-03 13:52:12 +08; 3s ago\r\n     Docs: http:\/\/supervisord.org\r\n Main PID: 18293 (supervisord)\r\n   CGroup: \/system.slice\/supervisor.service\r\n           \u2514\u250018293 \/usr\/bin\/python \/usr\/bin\/supervisord -n -c \/etc\/supervisor\/supervisord.conf\r\n\r\nMar 03 13:52:12 raspberrypi systemd&#x5B;1]: Started Supervisor process control system for UNIX.\r\nMar 03 13:52:14 raspberrypi supervisord&#x5B;18293]: 2018-03-03 13:52:14,741 CRIT Supervisor running as root (no user in config file)\r\nMar 03 13:52:14 raspberrypi supervisord&#x5B;18293]: 2018-03-03 13:52:14,743 WARN No file matches via include &quot;\/etc\/supervisor\/conf.d\/*.conf&quot;\r\nMar 03 13:52:14 raspberrypi supervisord&#x5B;18293]: 2018-03-03 13:52:14,794 INFO RPC interface 'supervisor' initialized\r\nMar 03 13:52:14 raspberrypi supervisord&#x5B;18293]: 2018-03-03 13:52:14,796 CRIT Server 'unix_http_server' running without any HTTP authentication checking\r\nMar 03 13:52:14 raspberrypi supervisord&#x5B;18293]: 2018-03-03 13:52:14,797 INFO supervisord started with pid 18293\r\n<\/pre>\n<h2>Preparing the virtual environment for running our Python 3 Flask application on Raspbian Stretch Lite<\/h2>\n<p>The next step is to prepare the virtual environment for running our Python 3 Flask application. To do so run the following commands:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ncd \/var\/flaskapp\/simpleapp\r\nvirtualenv -p python3 simpleappenv\r\nsource simpleappenv\/bin\/activate\r\npip install -r requirements.txt\r\ndeactivate\r\n<\/pre>\n<p>After the commands complete, we will have the virtual environment for running our Python 3 Flask application. This virtual environment will be available at the <code>\/var\/flaskapp\/simpleapp\/simpleappenv<\/code> directory. <\/p>\n<h2>Installing Gunicorn inside the virtual environment<\/h2>\n<p>The next step is to install Gunicorn into the virtual environment that we had created. To do so, we run the following commands:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ncd \/var\/flaskapp\/simpleapp\r\nsource simpleappenv\/bin\/activate\r\npip install gunicorn\r\ndeactivate\r\n<\/pre>\n<p>Installing <code>gunicorn<\/code> inside the virtual environment will ensure that Supervisor get the correct version of Gunicorn to run our Python 3 Flask application. Although it is possible to indicate Gunicorn as a dependency in <code>requirements.txt<\/code>, we left it out so that our Python 3 Flask application remains agnostic to the WSGI server that we use for deployment.<\/p>\n<h2>Change owner of the Python 3 Flask application directory to www-data<\/h2>\n<p>After we had installed Gunicorn inside the virtual environment, the next step will be to set the <code>www-data<\/code> user as the owner of our Python 3 Flask application:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo chown -R www-data:www-data \/var\/flaskapp\/simpleapp\r\n<\/pre>\n<h2>Creating the Supervisor configuration file to run our Python 3 Flask application via Gunicorn<\/h2>\n<p>By default, the Supervisor daemon will look inside the <code>\/etc\/supervisor\/conf.d<\/code> directory to look for instructions to get applications running. To get the Supervisor daemon to run our Python 3 Flask MVP as its subprocess, we first point <code>nano<\/code> to a configuration file inside the <code>\/etc\/supervisor\/conf.d<\/code> directory:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo nano \/etc\/supervisor\/conf.d\/simpleapp.conf\r\n<\/pre>\n<p>And then paste in the following contents:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;program:simple-flask-app]\r\ndirectory=\/var\/flaskapp\/simpleapp\r\ncommand=\/bin\/bash -E -c .\/start.sh\r\nautostart=true\r\nautorestart=true\r\nstopsignal=INT\r\nstopasgroup=true\r\nkillasgroup=true\r\nuser=www-data\r\n<\/pre>\n<p>This set of configurations will <a href=\"https:\/\/www.techcoil.com\/blog\/supervisor-configurations-to-ensure-that-my-python-flask-application-releases-binded-ports-during-a-supervisor-restart\/\" target=\"_blank\">ensure that our Python 3 Flask application releases binded port(s) during a supervisor restart<\/a>. In addition, we also indicated to Supervisor that we wanted to run our Python 3 Flask application as the <code>www-data<\/code> user.<\/p>\n<p>After we had created this set of configurations, we can restart Supervisor to get it to run our Python 3 Flask application for us:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo systemctl restart supervisor.service\r\n<\/pre>\n<p>You can verify whether your Python 3 Flask application is running successfully by using <code>supervisorctl<\/code>:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo supervisorctl\r\n<\/pre>\n<p>In the supervisor control panel, you will see something similar to the following output if your Python 3 Flask application is running successfully:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsimple-flask-app                 RUNNING   pid 24444, uptime 0:00:24\r\nsupervisor&gt; \r\n<\/pre>\n<p>You can also see the output from Gunicorn by running the following command in <code>supervisorctl<\/code>:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\ntail simple-flask-app stdout\r\n<\/pre>\n<p>Which will give output similar to the following:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24447] &#x5B;INFO] Starting gunicorn 19.7.1\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24447] &#x5B;INFO] Listening at: unix:simpleapp.sock (24447)\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24447] &#x5B;INFO] Using worker: sync\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24450] &#x5B;INFO] Booting worker with pid: 24450\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24451] &#x5B;INFO] Booting worker with pid: 24451\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24452] &#x5B;INFO] Booting worker with pid: 24452\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24453] &#x5B;INFO] Booting worker with pid: 24453\r\n&#x5B;2018-03-03 14:42:04 +0800] &#x5B;24454] &#x5B;INFO] Booting worker with pid: 24454\r\n<\/pre>\n<p>We will also see the <code>\/var\/flaskapp\/simpleapp\/simpleapp.sock<\/code> unix socket, which is where Nginx will proxy HTTP requests to.<\/p>\n<h2>Setting up Nginx to proxy HTTP request to our Python 3 Flask application<\/h2>\n<p>Once we are sure that Supervisor is running our Python 3 Flask application with Gunicorn, the next step is to configure Nginx to proxy HTTP requests to it. Suppose we want to reach our Python 3 Flask application via the domain name <code>simpleapp.techcoil.com<\/code>, we first use nano to create the <code>\/etc\/nginx\/sites-enabled\/simpleapp.techcoil.com<\/code> file:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nsudo nano \/etc\/nginx\/sites-enabled\/simpleapp.techcoil.com\r\n<\/pre>\n<p>And then include the following contents:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nserver {\r\n\r\n    server_name simpleapp.techcoil.com;\r\n    listen 80;\r\n    root \/var\/flaskapp\/simpleapp\/static;\r\n\r\n    location \/ {\r\n        try_files $uri @simpleapp-flask;\r\n    }\r\n\r\n    location @simpleapp-flask {\r\n        include proxy_params;\r\n        proxy_pass http:\/\/unix:\/var\/flaskapp\/simpleapp\/simpleapp.sock;\r\n    }\r\n\r\n}\r\n<\/pre>\n<p>With this set of Nginx configurations, we told Nginx to listen on port 80 for HTTP requests directed at the domain <code>simpleapp.techcoil.com<\/code>. For every such request, we tell Nginx to reference the directory <code>\/var\/flaskapp\/simpleapp\/static<\/code> as the document root. <\/p>\n<p>The <code>location \/<\/code> block tells Nginx to map request to a file inside the <code>\/var\/flaskapp\/simpleapp\/static<\/code> directory and return it as a HTTP response if there is one. If the file does not exist, Nginx should issue an internal redirect to the <code>location @simpleapp-flask<\/code> block.<\/p>\n<p>The <code>location @simpleapp-flask<\/code> block proxies HTTP requests to the <code>\/var\/flaskapp\/simpleapp\/simpleapp.sock<\/code> unix socket with some common HTTP headers defined inside the <code>\/etc\/nginx\/proxy_params<\/code> file.<\/p>\n<h2>Accessing our Python 3 Flask application with a computer in the same network<\/h2>\n<p>To verify that our Python 3 Flask application is accessible via <code>simpleapp.techcoil.com<\/code>, we will edit the host file on a computer that is in the same network as our Python 3 Flask application. <\/p>\n<p>Add the following entries inside the host file to map the <code>simpleapp.techcoil.com<\/code> domain to the IP address of the Raspberry Pi 3 that is running our Python 3 Flask application:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n192.168.1.109 simpleapp.techcoil.com\r\n<\/pre>\n<p>After you had done so, you should be able to use your browser to access your Python 3 Flask application via <code>http:\/\/simpleapp.techcoil.com<\/code>. The Python 3 Flask application should return you the HTTP response containing the <strong>Hello there, welcome to our app!<\/strong> message.<\/p>\n\n      <ul id=\"social-sharing-buttons-list\">\n        <li class=\"facebook\">\n          <a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fwp.me%2Fp245TQ-2B\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n            <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Facebook.png\" alt=\"Facebook icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"twitter\">\n          <a href=\"https:\/\/twitter.com\/intent\/tweet?text=&url=https%3A%2F%2Fwp.me%2Fp245TQ-2B&via=Techcoil_com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Twitter.png\" alt=\"Twitter icon\"> Tweet\n          <\/a>\n        <\/li>\n        <li class=\"linkedin\">\n          <a href=\"https:\/\/www.linkedin.com\/shareArticle?mini=1&title=&url=https%3A%2F%2Fwp.me%2Fp245TQ-2B&source=https:\/\/www.techcoil.com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/linkedin.png\" alt=\"Linkedin icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"pinterest\">\n          <a href=\"https:\/\/pinterest.com\/pin\/create\/button\/?url=https%3A%2F%2Fwww.techcoil.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F161&description=\" class=\"pin-it-button\" target=\"_blank\" role=\"button\" rel=\"nofollow\" count-layout=\"horizontal\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Pinterest.png\" alt=\"Pinterest icon\"> Save\n          <\/a>\n        <\/li>\n      <\/ul>\n    ","protected":false},"excerpt":{"rendered":"<p><a href=\"https:\/\/www.amazon.com\/Raspberry-Pi-RASPBERRYPI3-MODB-1GB-Model-Motherboard\/dp\/B01CD5VC92\/ref=as_li_ss_tl?ie=UTF8&#038;qid=1519745335&#038;sr=8-3&#038;keywords=Raspberry+Pi+3+board&#038;linkCode=ll1&#038;tag=clivsperswebs-20&#038;linkId=349641857f08826cc78099b4402f5f70\" rel=\"noopener\" target=\"_blank\">Raspberry Pi 3 Model B boards<\/a> make good <a href=\"https:\/\/www.techcoil.com\/shop\/for\/gifts-for-programmers\" rel=\"noopener\" target=\"_blank\">gifts for programmers<\/a> and if someone had gifted you with one, you may want to use it as a control center for interacting with various IoT sensors and devices at home.<\/p>\n<p>In such a situation, you may want to build a Python 3 <a href=\"http:\/\/flask.pocoo.org\/\" rel=\"noopener\" target=\"_blank\">Flask<\/a> application to present the web interface for accessing the control center.<\/p>\n<p>After you had built that Python 3 Flask application, the next step will be to deploy it on your Raspberry Pi 3 for serving HTTP requests. <\/p>\n<p>This post discusses how you can deploy a Python 3 Flask application on Raspberry Pi 3 with Raspbian Stretch Lite, <a href=\"http:\/\/nginx.org\/\">Nginx<\/a>, <a href=\"https:\/\/virtualenv.pypa.io\" rel=\"noopener\" target=\"_blank\">Virtualenv<\/a> and <a href=\"http:\/\/gunicorn.org\/\" rel=\"noopener\" target=\"_blank\">Gunicorn<\/a>.<\/p>\n","protected":false},"author":1,"featured_media":694,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":""},"categories":[375,4],"tags":[517,484,225,226,233,254,240,308,412,445,195,256,438,426],"jetpack_featured_media_url":"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/white-piece-with-port-openings-of-official-case-attached-to-red-parts-and-raspberry-pi-3-board.jpg","jetpack_shortlink":"https:\/\/wp.me\/p245TQ-2B","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/161"}],"collection":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/comments?post=161"}],"version-history":[{"count":0,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/161\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media\/694"}],"wp:attachment":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media?parent=161"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/categories?post=161"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/tags?post=161"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}