aboutsummaryrefslogtreecommitdiff
path: root/content/weblog/2018-07-21_building-deploying-personal-site-with-blog-pt2/index.md
blob: 5bfd1f1712add669fed28a93d52c66731120cdf6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
+++
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.

<!-- more -->

_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.