Skip to content

Commit 2158fe2

Browse files
author
Li Yin
committed
Merge conflicts
2 parents 3a02755 + c857166 commit 2158fe2

File tree

1 file changed

+217
-15
lines changed

1 file changed

+217
-15
lines changed

guides/DigitalOcean Tutorial.md

Lines changed: 217 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ If you are a first time learner, we do encourage you to go through the whole tut
77
- [DigitalOcean set-up](DigitalOcean%20Tutorial.md#digitalocean)
88
- [App deployment (applies to any hosting platform)](DigitalOcean%20Tutorial.md#deploying-applications-onto-our-server)
99
- [Creating a unix user](DigitalOcean%20Tutorial.md#creating-another-user)
10-
- [PostgreSQL user configuration](DigitalOcean%20Tutorial.md#configuring-our-user-for-postgresql)
11-
- [Setting up nginx](DigitalOcean%20Tutorial.md#setting-up-nginx)
12-
- [Setting up uWSGI](DigitalOcean%20Tutorial.md#setting-up-uwsgi)
10+
- [Postgres configuration](DigitalOcean%20Tutorial.md#configuring-postgres)
11+
- [Setting up nginx](DigitalOcean%20Tutorial.md#nginx)
12+
- [Setting up uWSGI](DigitalOcean%20Tutorial.md#uwsgi)
1313

1414
# DigitalOcean
1515
## Introduction
@@ -60,31 +60,33 @@ If you have successfully followed the tutorial so far, then you have finished al
6060

6161
## Connecting to our server
6262

63-
First, we need to SSH our server. Simply use the recommend:
63+
First, we need to SSH our server. Simply use the command:
6464

6565
```
6666
ssh root@<your server ip>
6767
```
6868

69-
and you will be asked for the root password. Beware that `SSH` command only works on Mac, not on windows. However, there are plenty of softwares that you can use to SSH from windows, `putty` is one popular option.
69+
and you will be asked for the root password. Beware that `SSH` command only works on Unix, not on Windows. However, there are plenty of softwares that you can use to SSH from Windows, [putty](http://www.putty.org/) is one popular choice.
7070

7171
## Installing required packages
7272

73-
After connecting to our server and logged in as root user, it is recommended to run the command
73+
After connecting to our server and logged in as root user, it is recommended to run the command below first to get all the available updates:
7474

7575
```
7676
apt-get update
7777
```
7878

79-
first to get all the available updates. Then we use the following command to install our required packages:
79+
Then we use the following command to install our required packages:
8080

8181
```
8282
apt-get install postgresql postgresql-contrib
8383
```
8484

85+
Note that this is a just an example to install different packages using one command, we may need more packages in the following sections.
86+
8587
## Creating another user
8688

87-
Since the `root` user is the most powerful, we may want to limit access to it to improve security. So in this section, we will create a new user and config it to "act like" a `root` user but with certain limitation. And we will be logging as this user from now on. It is highly recommended to do so, but if you choose not to follow and simply want to login as the `root` user nonetheless, you may click [here to skip to the next section](DigitalOcean%20Tutorial.md#configuring-our-user-for-postgresql).
89+
Since the `root` user is the most powerful, we may want to limit access to it to improve security. So in this section, we will create a new user and config it to "act like" a `root` user but with certain limitation. And we will be logging as this user from now on. It is highly recommended to do so, but if you choose not to follow and simply want to login as the `root` user anyway, you may click [here to skip to the next section](DigitalOcean%20Tutorial.md#configuring-postgres).
8890

8991
### Hello John Doe
9092

@@ -159,11 +161,17 @@ to enable our modifications.
159161

160162
Now we've created a new user `johndoe`, given it temporary super user privilege and enabled SSH for this user. Next, we'll be learning to link this user to our PostgreSQL database.
161163

162-
## Configuring our user for PostgreSQL
164+
## Configuring Postgres
163165

164-
Since PostgreSQL allows its own user to interact with the database, we will need to create an according user and configure it to access the database.
166+
Since Postgres allows its own user to interact with the database, we will need to create an according user and configure it to access the database.
165167

166-
### Creating a PostgreSQL user
168+
### Installing PostgreSQL
169+
170+
```
171+
apt-get install postgresql postgresql-contrib
172+
```
173+
174+
### Creating a Postgres user
167175

168176
We use the following command to create the user:
169177

@@ -172,7 +180,7 @@ sudo -i -u postgres
172180
createuser johndoe -P
173181
```
174182

175-
After inputing and confirming the password, we now have created a Postgres user. Notice that we use the same username `johndoe` to create the PostgreSQL user, since by default, Postgres only allows the unix user with the same name as its Postgres user to interact with it.
183+
After inputing and confirming the password, we now have created a Postgres user. Notice that we use the same username `johndoe` to create the Postgres user, since by default, Postgres only allows the unix user with the same name as its Postgres user to interact with it.
176184

177185
### Creating a PostgreSQL database for our user
178186

@@ -243,8 +251,9 @@ to enable password authentication.
243251

244252
*** important: *** SQLAlchemy will ***NOT*** work unless we do this modification.
245253

246-
## Setting up nginx
254+
## Nginx
247255

256+
Nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server. In this tutorial, we use nginx to direct traffic to our server. Nginx can be really helpful in scenarios like running our app on multiple thread, and it is of great performance that we do not need to worry about it slowing our app down. More details about nginx can be found [here](https://nginx.org/en/).
248257
### Installing nginx
249258

250259
```
@@ -266,15 +275,208 @@ sudo ufw add 'Nginx HTTP'
266275
sudo ufw add ssh
267276
```
268277

269-
Remember that the second line is just a precaution, it should be added already, but we don't want to get blocked out of the server!
278+
***important:*** Remember that the second line, adding SSH rules, is not related to nginx configuration, but since we're activating the firewall, we don't want to get blocked out of the server!
270279

271280
At last, if the UFW (Ubuntu Firewall) is inactive, use the command below to activate it:
272281

273282
```
274283
sudo ufw enable
275284
```
276285

286+
And at last, if we want to check if nginx is running, we may use the command:
287+
288+
```
289+
systemctl status nginx
290+
```
291+
292+
Some other helful command options for system controller are:
293+
294+
```
295+
systemctl start <service_name>
296+
systemctl restart <service_name>
297+
systemctl stop <service_name>
298+
```
299+
300+
### Configure nginx for our app
301+
302+
Before deploying our app onto the server, we need to configure nginx for our app. Use the below command to create a config file for our app:
303+
304+
```
305+
sudo vi /etc/nginx/sites-available/items-rest.conf
306+
```
307+
308+
Note that `items-rest` is what we named our service, you may change it accordingly, but remember to remain consistent throughout the configurations.
309+
310+
Next, we input the below text into `items-rest.conf` file. ***Remember to change your service name accordingly in this file as well***
311+
312+
```
313+
server {
314+
listen 80;
315+
real_ip_header X-Forwarded-For;
316+
set_real_ip_from 127.0.0.1;
317+
server_name localhost;
318+
319+
location / {
320+
include uwsgi_params;
321+
uwsgi_pass unix:/var/www/html/items-rest/socket.sock;
322+
uwsgi_modifier1 30;
323+
}
324+
325+
error_page 404 /404.html;
326+
location = /404.html {
327+
root /usr/share/nginx/html;
328+
}
329+
330+
error_page 500 502 503 504 /50x.html;
331+
location = /50x.html {
332+
root /usr/share/nginx/html;
333+
}
334+
335+
}
336+
```
277337

338+
Basically, the above config allows nginx to send the request, coming from our user, to our app. It also sets up some error pages for our service using nginx predefined pages.
278339

340+
And at last, in order to enable our configuration, we need to do something like this:
341+
342+
```
343+
sudo ln -s /etc/nginx/sites-available/items-rest.conf /etc/nginx/sites-enabled/
344+
```
345+
346+
### Setting up our app folder
347+
348+
First, we create a folder for our app:
349+
350+
```
351+
sudo mkdir /var/www/html/items-rest
352+
```
353+
354+
Since the folder is owned by root user, and if we are using another user, we need to transfer ownership to our current user:
355+
356+
```
357+
sudo chown johndoe:johndoe /var/www/html/items-rest
358+
```
359+
360+
Remember that `johndoe` is the username in our tutorial, make sure you change it to yours accordingly. Same goes for `items-rest`.
361+
362+
Next, we get our app from Git:
363+
364+
```
365+
cd /var/www/html/items-rest/
366+
git clone https://github.com/schoolofcode-me/stores-rest-api.git .
367+
```
368+
369+
Note that there's a trailing space and period (` .`)at the end, which tells git the destination is the current folder. If you're not in this folder `/var/www/html/items-rest/`, remember to switch to it or explicitly specify it in the git command. And for the following commands in this section, we all assume that we are inside the folder `/var/www/html/items-rest/` unless specified otherwirse.
370+
371+
In order to store logs, we need to create a log folder, (under `/var/www/html/items-rest/`):
372+
373+
```
374+
mkdir log
375+
```
376+
377+
Then we will install a bunch of tools we need to set up our app:
378+
379+
```
380+
sudo apt-get install python-pip python3-dev libpq-dev
381+
```
279382

280-
## Setting up uWSGI
383+
Next, to install `virtualenv`:
384+
385+
```
386+
pip install virtualenv
387+
```
388+
389+
After it is installed, we can create a virtualenv:
390+
391+
```
392+
virtualenv venv --python==python3.5
393+
```
394+
395+
Note that Ubuntu usually comes with `Python3.5` and it is what we used in the sample code, if you choose to use different version of Python, feel free to change it accordingly, and it will be the Python version inside your virtualenv.
396+
397+
To activate virtualenv:
398+
399+
```
400+
source venv/bin/activate
401+
```
402+
403+
You should see `(venv)` appears at the start of your command line now. And we assume that we are in virtualenv for all the following commands in this section unless specified otherwise.
404+
405+
Next, use the command below to install the specified dependencies:
406+
407+
```
408+
pip install -r requirements.txt
409+
```
410+
411+
Note that `requirement.txt` is a text file that includes all the dependencies that we created in our Git folder. If you haven't done so, we highly recommend you to. We will not cover this because we don't want to diverge and confuse our readers.
412+
413+
And we will set up uWSGI in next section and finish deploying our app.
414+
415+
416+
## uWSGI
417+
418+
We will be using uWSGI to run the app for us, in this way, we can run it in multiple threads within multiple processes. It also allow us to log more easily. More details on uWSGI can be found [here](https://uwsgi-docs.readthedocs.io/en/latest/).
419+
420+
First, we define a uWSGI service in the system by:
421+
422+
```
423+
sudo vi /etc/systemd/system/uwsgi_items_rest.service
424+
```
425+
426+
And the content we are going to input is shown below:
427+
428+
```
429+
[Unit]
430+
Description=uWSGI items rest
431+
432+
[Service]
433+
Environment=DATABASE_URL=postgres://johndoe:<johndoe_postgres_password>@localhost:5432/johndoe
434+
ExecStart=/var/www/html/items-rest/venv/bin/uwsgi --master --emperor /var/www/html/items-rest/uwsgi.ini --die-on-term --uid johndoe --gid johndoe --logto /var/www/html/items-rest/log/emperor.log
435+
Restart=always
436+
KillSignal=SIGQUIT
437+
Type=notify
438+
NotifyAccess=all
439+
440+
[Install]
441+
WantedBy=multi-user.target
442+
```
443+
444+
We will explain the basic idea of these configs. Each pair of square brackets `[]` defines a `section` which can contain some properties.
445+
446+
The `Unit` section simply provides some basic description and can be helpful when looking at the logs.
447+
448+
The `Service` section contains several properties related to our app. The `Environment` properties defines all the environment variables we need in our code. In our sample code, we want to retrieve the DATABASE_URL from system environment. And this is the place where you should keep all your secrets, such as secret keys and credentials. Beware that the `DATABASE_URL` should follow the format:
449+
450+
```
451+
<database_type>://<db_username>:<db_user_password>@localhost:<db_port>/<db_name>
452+
```
453+
454+
The `ExecStart` proterty informs uWSGI on how to run our app as well as log it.
455+
456+
At last, the `WantedBy` property in `Install` section allows the service to run as soon as the server boots up.
457+
458+
***important:*** Remember to change the username, password, database name and service name/folder accordingly in your own code.
459+
460+
```
461+
[uwsgi]
462+
base = /var/www/html/items-rest
463+
app = run
464+
module = %(app)
465+
466+
home = %(base)/venv
467+
pythonpath = %(base)
468+
469+
socket = %(base)/socket.sock
470+
471+
chmod-socket = 777
472+
473+
processes = 8
474+
475+
threads = 8
476+
477+
harakiri = 15
478+
479+
callable = app
480+
481+
logto = /var/www/html/items-rest/log/%n.log
482+
```

0 commit comments

Comments
 (0)