Components used for this article:
- VPS: Linode
- OS: Ubuntu 14.04 LTS
- Web server: Nginx
- WSGI server: Gunicorn
- Application framework: Pyramid
- Relational database: PostgreSQL
- NoSQL data store: Redis
- Python version: 3.4
Suppose that we already installed an Ubuntu image on a Linode plan.
Update packages
sudo apt-get update && apt-get upgrade
DNS resolution
Add a A record
for the domain name of the application.
Nginx
Install Nginx
sudo apt-get install nginx
Configure Ngnix
Create a cofiguration file under /etc/nginx/conf.d/
with name [app_name].conf
.
sudo nano /etc/nginx/conf.d/[app_name].conf
Configure without https
Template of /etc/nginx/conf.d/[app_name].conf
:
upstream app_server_wsgiapp {
server localhost:8000 fail_timeout=0;
}
server {
listen 80;
# make sure to change the next line to your own domain name!
server_name appname.example.com;
access_log /var/log/nginx/appname.access.log;
error_log /var/log/nginx/appname.error.log info;
keepalive_timeout 5;
# nginx serve up static files and never send to the WSGI server
location /static {
autoindex on;
alias /home/username/appname/static;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server_wsgiapp;
break;
}
}
# this section allows Nginx to reverse proxy for websockets
location /socket.io {
proxy_pass http://app_server_wsgiapp/socket.io;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
Configure with https
(to add)
Restart nginx
Delete default website file:
sudo rm /etc/nginx/sites-enabled/default
Apply new configuration:
sudo service nginx restart
PostgreSQL
Install PostgreSQL
sudo apt-get install postgresql libpq-dev postgresql-client-common postgresql-client
then create database and new user
# switch to postgres user
sudo su - postgres
# create database
createdb dbname
# create a non-root database user and set password
createuser --superuser username
psql
ALTER USER username WITH PASSWORD 'password'
(For me, it seems that the last line would take effect, but we can change the password later.)
Press CTRL-D
to quit psql
, and CTRL-D
again to quit postgres user.
Now database dbname
is created and user username
is able to access the database.
# Connect to database
psql dbname
# Show tables
dt
Change password of current user:
password
Redis
Install Redis
sudo apt-get install redis-server
Test using redis-cli
.
Python application
Install pip, virtualenv
sudo apt-get install python3-pip
sudo apt-get install python3.4-venv
sudo python3 -m pip install virtualenv virtualenvwrapper
Note: python3.4-venv
not python3-venv
Make virtualenv
# set an environment variable to where you want your virtual environment
export VENV=~/env
# create the virtual environment
python3 -m venv $VENV
Upgrade packages in virtualenv
$VENV/bin/pip install --upgrade pip setuptools
“Why use $VENV/bin/pip
instead of source bin/activate
, then pip
?” From Pyramid docs:
$VENV/bin/pip clearly specifies that pip is run from within the virtual environment and not at the system level.
activate drops turds into the user’s shell environment, leaving them vulnerable to executing commands in the wrong context. deactivate might not correctly restore previous shell environment variables.
Although using source bin/activate, then pip, requires fewer key strokes to issue commands once invoked, there are other things to consider. Michael F. Lamb (datagrok) presents a summary in Virtualenv’s bin/activate is Doing It Wrong.
Ultimately we prefer to keep things clear and simple, so we use $VENV/bin/pip.
Pyramid
Install Pyramid
# install pyramid
$VENV/bin/pip install pyramid
# or for a specific released version
$VENV/bin/pip install "pyramid==1.7.3"
Demo app
We create a demo app using scaffold provided by Pyramid.
$VENV/bin/pcreate -s starter demo
cd demo
$VENV/bin/pip install -e .
WSGI server
Install Gunicorn
$VENV/bin/pip install gunicorn
Run the demo app:
cd ~/demo
$VENV/bin/gunicorn --paste development.ini -b :8000
8000
is the port gunicorn listens from the nginx reverse proxy, which we set in /etc/nginx/conf.d/demo.conf
.
Open a browser and visit the URL and the app should be running.
Start gunicorn server with supervisor
Install supervisor
sudo apt-get install supervisor
Configure supervisor. Create a file /etc/supervisor/conf.d/[app_name].conf
, and add lines: (e.g., for demo app, the file name should be demo.conf
)
[program:demo]
environment=DEBUG=False
command=/home/[username]/venv/bin/gunicorn --paste [path/to/app/]development.ini -b :8000 --chdir [path/to/app]
directory=/home/[username]/demo
user=[username]
autostart=true
autorestart=true
redirect_stderr=True
Start supervisor service:
sudo service supervisor start
Visit the URL and the app should be running.