Last active
February 21, 2017 00:57
-
-
Save Lapicher/c6d686b121a4a71eb5a024eb49d6a72f to your computer and use it in GitHub Desktop.
Revisions
-
kasappeal revised this gist
Jan 24, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,7 @@ This guide shows how to setup a production environment for a Django application Install PostgreSQL and Nginx using: ```bash sudo apt-get install -y postgresql-9.5 postgresql-contrib-9.5 postgresql-server-dev-9.5 nginx git circus make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils python-setuptools ``` ## Creating a user to run the application -
kasappeal revised this gist
Nov 3, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,7 @@ This guide shows how to setup a production environment for a Django application Install PostgreSQL and Nginx using: ```bash sudo apt-get install -y postgresql-9.5 postgresql-contrib-9.5 postgresql-server-dev-9.5 nginx git circus make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils ``` ## Creating a user to run the application -
kasappeal revised this gist
Nov 3, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,7 @@ This guide shows how to setup a production environment for a Django application Install PostgreSQL and Nginx using: ```bash sudo apt-get install -y postgresql-9.5 postgresql-contrib-9.5 postgresql-server-dev-9.5 nginx git circus build-essential ``` ## Creating a user to run the application -
kasappeal created this gist
Oct 25, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,389 @@ # How to deploy a Django app with PostgreSQL + Gunicorn + Nginx using pyenv on Ubuntu Server 16.04 This guide shows how to setup a production environment for a Django application using PostgreSQL as database, Gunicorn as application server and Nginx as http server using Ubuntu Server 14.04 as Operative System. ## Install PosgreSQL, Nginx, Git and Circus Install PostgreSQL and Nginx using: ```bash sudo apt-get install -y postgresql-9.5 postgresql-contrib-9.5 postgresql-server-dev-9.5 nginx git circus ``` ## Creating a user to run the application For security reasons, it's a good practice to run web applications as a user with no root privileges so that, if the web applications allows some code execution due to a bug, the code never will adquire root privileges to hack the server. Create the user: ```bash sudo adduser <app_name> ``` Lock user account to deny users login via username and password to the server: ```bash sudo passwd -l <app_name> ``` Add the nginx user (usually `www-data`) to the `<app_name>` group to have read privileges: ```bash sudo adduser www-data <app_name> ``` ## Creating database and allow app user to the database We have to create a database to store all application info and allow the `<app_name>` user to acces that database. Creating database user: ```bash sudo -u postgres createuser <app_name> ``` Creating database a giving `<app_name>` access to it: ```bash sudo -u postgres createdb <app_name> -O <app_name> ``` ## Becoming `<app_name>` user We have to clone the application in the `<app_name>` user home as the home user. Due to we locked the `<app_name>` user, we cannot login to the server with that username. Instead, we're going to become the `<app_name>` user from our root user by using: ```bash sudo -u <app_name> -i ``` Now, we are logged as the `<app_name>` user and in the `<app_name>` user home. We can check it with `pwd`: ```bash pwd /home/<app_name> ``` ## Install pyenv and pyenv-virtualenv `pyenv` allow us to install any Python's version in our user account. We are going to user `pyenv` to create a virtualenvironment with the Python's version we need. To install `pyenv` and `pyenv-virtualenv` we need to checkout the project from github: ```bash git clone https://github.com/yyuu/pyenv.git ~/.pyenv git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv ``` After that, we need to update our `.bash_profile` to make pyenv work properly: ```bash echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile echo 'eval "$(pyenv init -)"' >> ~/.bash_profile echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile ``` Now we need to logout and login again as `<app_name>` user_ ```bash logout sudo -u <app_name> -i ``` ## Installing our Python version and creating a virtualenv ### Installing Python's version needed To install the Python's version needed to run our app we can use `pyenv`: ```bash pyenv install <python_version> ``` Example: ```bash pyenv install 3.5.2 ``` Note that the Python's version will be installed in: `/home/<app_name>/.pyenv/versions/<python_version>` ### Creating a virtualenv using the Python's version installed Now we can use 'pyenv-virtualenv' to create a virtualenv based on the installed Python's version: ```bash pyenv virtualenv <python_version> <virtualenv_name> ``` Example: ```bash pyenv virtualenv 3.5.2 env ``` Note that the virtualenv will be created in: `/home/<app_name>/.pyenv/versions/<virtualenv_name>` ## App scaffolding and setup ### Clonning the app Now we can clone our Django project using `git` in a folder named `app` (this name is optional, obviously): ```bash git clone <repo_url> app ``` ### Logs folder We will create a folder called `logs` to store all logs generated by the application: ```bash mkdir logs ``` ### Production settings As a good practice, we must use a different settings for development and production because **we must not store production data in the repo**. So that, we will create a `settings_production.py` to run the application in production: ```bash nano app/<app_name>/settings_production.py ``` And we will all the settings needed for production but using environment variables (set by a root-privileged user): ```python import os from settings import * DEBUG = False TEMPLATE_DEBUG = False ALLOWED_HOSTS = ['*'] SECRET_KEY = os.environ.get('SECRET_KEY', SECRET_KEY) ADMINS = (( os.environ.get('ADMIN_EMAIL_NAME', ''), os.environ.get('ADMIN_EMAIL_ADDRESS', '') ),) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': os.environ.get('DB_NAME', ''), 'USER': os.environ.get('DB_USER', '') } } STATIC_ROOT = os.path.join(BASE_DIR, os.environ.get('STATIC_ROOT', "static/")) STATIC_URL = os.environ.get('STATIC_URL', STATIC_URL) MEDIA_ROOT = os.path.join(BASE_DIR, os.environ.get('MEDIA_ROOT', "media/")) MEDIA_URL = os.environ.get('MEDIA_URL', "/media/") ``` ### Installing project's dependencies and gunicorn in virtualenv Now we have to activate the virtualenv: ```bash pyenv activate env ``` Befor install any package, we should update pip: ```bash pip install --upgrade pip ``` Now we can install project dependencies: ```bash pip install -r app/requirements.txt ``` And gunicorn: ```bash pip install gunicorn ``` ### Aplying migrations, collecting static files and create super user Once we have all dependencies installed, we have to apply Django migrations to our database and collect static files to be served from Nginx as static content. But before that, we have to export the environment variables related to the database in order to be loaded from the `settings_production file`: ```bash export SECRET_KEY=<secret_key> export DB_NAME=<app_name> export DB_USER=<app_name> export DJANGO_SETTINGS_MODULE=<app_name>.settings_production ``` Now, access to `app` folder: ```bash cd app ``` Apply migrations: ```bash python manage.py migrate ``` Collect static files: ```bash python manage.py collectstatic --noinput ``` Create super user: ```bash python manage.py createsuperuser ``` ## Deactivating virtualenv and logout as app user Now we are done with all the stuff as `<app_name>` user, so that we have to deactivate virtualenv with: ```bash pyenv deactivate ``` and `logout` to become a root-privileged user: ```bash logout ``` # Setting up circus to run gunicorn Now we have to install circus, a process manager written in Django that we will use to run gunicorn as a service. ## App gunicorn settings Let's create a file in `/etc/circus/conf.d` called `<app_name>.ini` to setup all the gunicorn running configuration: ```bash sudo nano /etc/circus/conf.d/<app_name>.ini ``` The file must have this settings but replacing `<variables>` for their values: ``` [watcher:<app_name>] working_dir = /home/<app_name>/app cmd = gunicorn args = -w 1 -t 180 --pythonpath=. -b unix:/home/<app_name>/app.sock <app_name>.wsgi uid = <app_name> numprocesses = 1 autostart = true send_hup = true stdout_stream.class = FileStream stdout_stream.filename = /home/<app_name>/logs/gunicorn.stdout.log stdout_stream.max_bytes = 10485760 stdout_stream.backup_count = 4 stderr_stream.class = FileStream stderr_stream.filename = /home/<app_name>/logs/gunicorn.stderr.log stderr_stream.max_bytes = 10485760 stderr_stream.backup_count = 4 [env:<app_name>] PATH = /home/<app_name>/.pyenv/versions/env/bin:$PATH TERM = rxvt-256color SHELL = /bin/bash USER = <app_name> LANG = en_US.UTF-8 HOME = /home/<app_name>/app PYTHONPATH = /home/<app_name>/.pyenv/versions/env/lib/python<PYTHON_VERSION_WITHOUT_LAST_NUMBER>/site-packages DJANGO_SETTINGS_MODULE = <app_name>.settings_production SECRET_KEY = <secret_key> DB_NAME = <app_name> DB_USER = <app_name> ``` Now, we only have to run circus: ```bash sudo service circus start ``` # Nginx setup Ok, let's finish by setting up nginx to catch the traffic for a given domain and redirect it to gunicorn to serve dynamic content. Let's create a file in `/etc/nginx/sites-available` called `<app_name>`: ```bash sudo nano /etc/nginx/sites-available/<app_name>` ``` The file must have this settings but replacing `<variables>` for their values: ``` server { listen 80; server_name <your_domain>; access_log /home/<app_name>/logs/nginx-access.log; error_log /home/<app_name>/logs/nginx-error.log; root /home/<app_name>/app/; client_max_body_size 10M; location /static { alias /home/<app_name>/app/static; } location /media { alias /home/<app_name>/app/media; } location / { include proxy_params; proxy_pass http://unix:/home/<app_name>/app.sock; } } ``` Now we have to make a symlink from the `sites-available` folder to `sites-enabled` folder: ```bash sudo ln -s /etc/nginx/sites-available/<app_name> /etc/nginx/sites-enabled/<app_name> ``` And now, test the config with: ```bash sudo nginx -t ``` You should receive: ``` nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Ok, let's gonna restart nginx: ```bash sudo service nginx restart ``` # Here we go! Just open `http://<your_domain>/admin/` in your browser!