+++ title = "Building and deploying a personal site with blog. Part 2" date = 2018-07-21T22:26:00Z +++ Welcome back, this post is a continuation of the previous post in which I wrote about how to initialize and setup a Django project for a personal site with blog locally. Now we will be focusing on the juicy part, getting your site deployed so that everyone on the interwebz can get to see ~~your nice new dank memes in your very own site!~~ the fruits of your sweat and blood. _You might want to read [part one](/weblog/building-deploying-personal-site-with-blog-pt1/)_ ## Part II: Deploying your site I will assume that you already have bought a VPS or dedicated server in any of the many hosting services available online, or maybe if you are cool enough, might even have a machine of your own with a properly setup static IP address. Note that if you are using shared hosting, the deployment process is usually already automatized if they have support for Python and Django, if they don't support Python and Django, you need to get another hosting solution. If you still don't have any kind of hosting, and you are looking for a nice and comfy VPS for your projects, I would recommend using DigitalOcean, you can get a VPS powerful enough for Django and other Python web projects for as low as $5. You can follow this referral link if you have decided to try DigitalOcean, it will give a $10 credit for your first account, enough for two whole months on their most inexpensive VPS. Once you have your server set and ready to go, we can continue with the fun part. Deploying your site. I will be assuming that you have a Debian-based distro in your server. ### First steps First let's make sure that our server is up to date ```sh $ sudo apt-get update $ sudo apt-get upgrade ``` Next, we need to install all the needed packages ```sh $ sudo apt-get install python3 python3-pip python-virtualenv postgresql nginx supervisor ``` You can set the virtual environment with your login user, or create another user exclusively to run your Django project and other related stuff. You can add a user to run the app like so ```sh $ adduser webuser ``` Let's go ahead and create a directory for virtual environments and create the environment for our project ```sh $ virtualenv mysite -p python3 ``` Now we source the environment ```sh $ source mysite/bin/activate ``` And use pip to install the necessary modules ```sh $ pip install Django Pillow psycopg2 django-summernote w3blog ``` After that, we start and enable postgresql ```sh $ sudo systemctl start postgresql $ sudo systemctl enable postgresql ``` Login to the postgres shell, set the password for user postgres, and create the database for our project ```sh $ sudo su - postgres $ psql postgres=# \password postgres=# create database mysitedb; ``` In this case, I am using the postgres user directly since I am using this server just for myself, and I only use PSQL for my blog. However, if you host multiple projects, and/or multiple users have a more direct access to postgres, you might want to create separate users and roles for each database or group of databases. ### Copying your Django project to the server One way to copy your project files to the server would be using scp, for example ```sh scp -r /path/to/project user@serveripordomain:/home/webuser/ ``` Or if you are already hosting your project as a git repository in a service like GitHub or BitBucket, you could clone directly into you repository in the home folder, like so ```sh $ git clone https:/github.com/user/repo ``` After the files have been copied, we need to set some things up for our Django project. Before running this commads, you might need to export the needed environmental variables, if you set up your Django settings using environmental variables as I wrote in the first part. Otherwise, you might want to edit your settings.py file now with the correct settings. First we collect static files ```sh $ ./manage.py collectstatic ``` Then, we migrate our models to the database ```sh $ ./manage.py migrate ``` And after migrating we create a superuser for the Django admin ```sh $ ./manage.py createsuperuser ``` If you get an authentication error while performing any of the above commands, you will have to edit the following file ```sh $ sudoedit /etc/postgresql/9.1/main/pg_hba.conf ``` Change this line ``` local all postgres peer ``` So that it looks like this ``` local all postgres md5 ``` ### Configuring the server I will be assuming that you are going to use nginx as a proxy server for Django. There are other alternatives such as Apache, but I found nginx to be a really powerful and easy to setup server. First, while in our virtual environment, we will install gunicorn. We might have been using Django's own development server while building and testing our app locally, but that's what it is, a development server. It is not mean for production, so we will use gunicorn for that ```sh pip install gunicorn ``` Now we'll cd into our env's bin folder and create a file called `gunicorn_start`, and add the following lines to it: ```sh #!/bin/bash NAME="mysite" # Our site's directory DIR=/home/webuser/mysite USER=webuser GROUP=webuser WORKERS=3 BIND=127.0.0.1:8001 DJANGO_SETTINGS_MODULE=mysite.settings DJANGO_WSGI_MODULE=mysite.wsgi LOG_LEVEL=error cd $DIR source /home/webuser/venvs/mysite/bin/activate export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE export PYTHONPATH=$DIR:$PYTHONPATH # This are the environment variables needed for your Django settings # (see the first part of this guide) export SITE_SECRETKEY="YOURSECRETKEYGOESHERE" export SITE_DEBUG="false" export SITE_DBPASSWORD="YOURPOSTGRESPWDGOESHERE" export SITE_DBUSER="postgres" export SITE_HOST="localhost" export SITE_PORT="5342" exec /home/webuser/venvs/mysite/bin/gunicorn ${DJANGO_WSGI_MODULE}:application \ --name $NAME \ --workers $WORKERS \ --user=$USER \ --group=$GROUP \ --bind=$BIND \ --log-level=$LOG_LEVEL \ --log-file=- ``` And make it executable ```sh $ chmod a+x gunicorn_start ``` That's almost it, but before actually running gunicorn, we will install one more program which will take care of the gunicorn server, so that if for any reason we need to reboot our server, it will restart gunicorn for us. It needs to be some kind of supervisor. Well why my dear friend, we are going to use Supervisor. But first, let's create a folder name logs inside our webuser's home folder, and create a file to be used to log any application errors: ```sh $ mkdir logs $ touch logs/gunicorn.log ``` Now we create a new Supervisor config file: ```sh $ sudoedit /etc/supervisor/conf.d/mysite.conf ``` Add the following: ```cfg [program:mysite] command=/home/webuser/venvs/mysite/bin/gunicorn_start user=webuser autostart=true autorestart=true redirect_stderr=true stdout_logfile=/home/webuser/logs/gunicorn.log ``` We reread the Supervisor configuration files, and start the program: ```sh $ sudo supervisorctl reread $ sudo supervisorctl update ``` And check the status to make sure it is running fine and dandy ```sh $ sudo supervisorctl status mysite ``` Next we should configure nginx, and for that we are going to make the configuration file for our site. Open it up ```sh $ sudoedit /etc/nginx/sites-available/mysite ``` And add the following lines ```nginx server { listen 80; listen [::]:80; server_name www.example.com; location /static/ { alias /home/webuser/mysite/static/; } location /media/ { alias /home/webuser/mysite/media/; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://127.0.0.1:8001; } } ``` I won't be explaining in this guide how to setup an SSL certificate, since it is out of its scope, but, if you want to get a free certificate, I cant point you to letsencrypt.com. It is backed by many of the top internet organizations. If you already have an SSL certificate, and would like to use HTTPS, your file should look like this ```nginx server { listen 80; listen [::]:80; server_name www.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name www.example.com; ssl_certificate /path/to/cert/fullchain.pem; ssl_certificate_key /path/to/key/privkey.pem; location /static/ { alias /home/webuser/mysite/static/; } location /media/ { alias /home/webuser/mysite/media/; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://127.0.0.1:8001; } } ``` After creating the needed config file, we create a symbolic link to it in sites-enabled ```sh $ sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite ``` Remove the default nginx site ```sh $ sudo rm /etc/nginx/sites-enabled/default ``` Finally, we restart nginx ```sh $ sudo service nginx restart ``` Et voila! ![It's alive!](result.png) ## Final thoughts This was by no means the most comprehensive guide to Django, but it might help you get started on setting up your own projects, and most importantly, actually deploying them to a live server.