diff --git a/guides/DigitalOcean Tutorial.md b/guides/DigitalOcean Tutorial.md index db5175d4..589d781b 100644 --- a/guides/DigitalOcean Tutorial.md +++ b/guides/DigitalOcean Tutorial.md @@ -1,9 +1,11 @@ # Overview -This is a tutorial on deploying our sample app onto DigitalOcean, a cloud computing platform. We will walk through whole process from creating an account to setting up a server instance and running your app on it. The process should be similar for any cloud computing services, more specifically, once you set up your server on any platform of your choice, the remaining deploying steps should be identical. So this tutorial may serve as a general guide on deploying your python app onto any hosting platforms. +This is a tutorial on deploying our app onto DigitalOcean, a cloud computing platform. We will walk through whole process from creating an account to setting up a server instance and running your app on it. The process should be similar for any cloud computing services. Once you set up your server on any platform of your choice the remaining deploying steps should be identical. This tutorial may serve as a general guide on deploying your Python app onto any hosting platforms. ## Quick links + If you are a first time learner, we do encourage you to go through the whole tutorial. However, if you are just looking for help on a specific task, here are the links to the sections you may want to refer to: + - [DigitalOcean set-up](DigitalOcean%20Tutorial.md#digitalocean) - [App deployment (applies to any hosting platform)](DigitalOcean%20Tutorial.md#deploying-applications-onto-our-server) - [Creating a unix user](DigitalOcean%20Tutorial.md#creating-another-user) @@ -14,15 +16,15 @@ If you are a first time learner, we do encourage you to go through the whole tut # DigitalOcean ## Introduction -DigitalOcean is a cloud infrastructure provider focused on simplifying web infrastructure for software developers. Basically, it allows you to rent servers with different performance at different cost. For more detailed information, you may refer to the official website help page [here](https://www.digitalocean.com/help/). +DigitalOcean is a cloud infrastructure provider focused on simplifying web infrastructure for software developers. It allows you to rent servers with different performance at different cost. For more detailed information, you may refer to the official website help page [here](https://www.digitalocean.com/help/). ## Creating an account -In this tutorial, we'll be offering you a $10 coupon, which can cover the cost of the most basic tier of server for 2 months. And of course you may choose to use it for higher tiers but for a shorter period. Simply click this link to create your account to get the $10 coupon: [https://m.do.co/c/d54c088544ed](https://m.do.co/c/d54c088544ed). If the link doesn't work, simply paste it into your browser. +You can sign up to DigitalOcean using our affiliate link. Doing so gives you a starting credit of $10, which allows you to rent a server for 2 months. Click this link to create your account and get the $10: [https://m.do.co/c/d54c088544ed](https://m.do.co/c/d54c088544ed). If the link doesn't work, paste it into your browser. ![Create an account](assets/DigitalOcean/create_account.png) -After clicking the link, you should be seeing a page like above. Simply create your account at the left-bottom corner and you'll receive the $10 coupon automatically. Beware that you'll be asked to provide payment info when creating the account, since all services (you chose) in DigitalOcean will be charged. +After clicking the link, you should see a page like the above. Create your account at the left-bottom corner and you'll receive the $10 automatically. Beware that you'll be asked to provide payment info when creating the account, since all services (which you'll choose below) in DigitalOcean will be charged after your credit runs out. ## Creating a Droplet @@ -30,19 +32,19 @@ A server instance in DigitalOcean is called a `Droplet`. It's just a name that m ### Choosing an image -To create a `Droplet`, we must first specify an image, that is, choosing what Operating System you want for the server. We recommend to use Ubuntu LTS (Long Term Support) distribution. For more info on Ubuntu life time, please refer to the [official Ubuntu end of life page here](https://www.ubuntu.com/info/release-end-of-life). In our example, we'll use `Ubuntu 16.04.* x64`, which is a LTS distribution. +To create a `Droplet`, we must first specify an image, that is, choosing what Operating System you want for the server. We recommend to use an Ubuntu LTS (Long Term Support) distribution. For more info on Ubuntu life time, please refer to the [official Ubuntu end of life page here](https://www.ubuntu.com/info/release-end-of-life). In our example, we'll use `Ubuntu 16.04.* x64`, which is an LTS distribution. ### Choosing a size -Next, we need to choose the specs for our server. In this tutorial, we'll be using the most basic tier of a Standard `Droplet`, which offers a single CPU with 512MB RAM, 20GB SSD and 1000 GB transfer at $5 per month. Generally, it's more than enough for testing personal applications, you may also run several services at a single Droplet. +Next, we need to choose the specs for our server. In this tutorial, we'll be using the most basic tier of a Standard `Droplet`, which offers a single CPU with 512MB RAM, 20GB SSD and 1000 GB transfer at $5 per month. Generally, it's more than enough for running personal applications. You may also run several services in a single Droplet. ### Choosing a datacenter region -Generally, choosing a region that's closest to your users will make your service deliver faster. +Generally, choosing a region that's _closest to your users_ will make your service deliver faster. If your users are primarily in the United States, you could choose a United States-based Droplet. ### Other configurations -In our example, we do not need to add any other services such as block storage or private network. So we will ignore these settings to keep our setting up simple and cheap. You may choose to use your own SSH key or you can just leave it unchecked and a password will be generated for you. At last, you may change the name of your `Droplet` to something you like and then click Create to create and launch your `Droplet`. +In our example, we do not need to add any other services such as block storage or private network. So we will ignore these settings to keep our setup simple and cheap. You may choose to use your own SSH key or you can just leave it unchecked and a password will be generated for you. At last, you may change the name of your `Droplet` to something you like and then click Create to create and launch your `Droplet`. ## Connecting to our droplet @@ -52,7 +54,7 @@ Once you've created your `Droplet`, you will receive an email containing your lo ### Change your password -Now you will be prompt a console connected to your `Droplet`. Use the login `root` and the password received in your email to login. Then you will be ask to provide your password again and change it to a new password. Notice that all password field will not show any modification when you are typing, there is nothing wrong with your console, it's just a Ubuntu security feature. After changing your password, you are now logged in as the root user on your server. +Now you will be shown a console connected to your `Droplet`. Use the login `root` and the password received in your email to login. Then you will be ask to provide your password again and change it to a new password. Notice that all password field will not show any modification when you are typing. There is nothing wrong with your console, it's just a Ubuntu security feature. After changing your password, you are now logged in as the root user on your server. If you have successfully followed the tutorial so far, then you have finished all the setting-ups that are specific to DigitalOcean. The following sections can serve as a standalone tutorial and can be applied to deployment onto any other platforms as well. @@ -66,11 +68,11 @@ First, we need to SSH our server. Simply use the command: ssh root@ ``` -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. +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 a popular choice. ## Installing required packages -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: +After connecting to our server and logging in as the `root` user, it is recommended to run the below command first to get all the available updates: ``` apt-get update @@ -93,10 +95,10 @@ Since the `root` user is the most powerful, we may want to limit access to it to In this section, we will create a user named `johndoe`. You may choose any name you want, just remember to swap `johndoe` with your username for each command. We create a new user `johndoe` with the following command: ``` -adduser johndow +adduser johndoe ``` -You will be asked to enter and retype the password for this user, and then provide some info about this user. Notice that you can leave the info sections blank if you want to. And if you *managed* to enter unmatching passwords, simply proceed to complete the info section and we can set up the password later by using command: +You will be asked to enter and retype the password for this user, and then provide some info about this user. Notice that you can leave the info sections blank if you want to. And if you entered unmatching passwords, just complete the info section and we can change the password later by using the command: ``` passwd johndoe @@ -117,7 +119,7 @@ first, and we will see a text file popping up. Then we navigate to the lines con root ALL=(ALL:ALL) ALL ``` -and we need to add a new line for our user in this section: +You can do this with the arrow keys. We need to add a new line for our user in this section: ``` # User privilege specification @@ -125,13 +127,13 @@ root ALL=(ALL:ALL) ALL johndoe ALL=(ALL:ALL) ALL ``` -Remember that the `ALL` has to be ***all-caps***, otherwise it will raise syntax error. +Remember that the `ALL` has to be **all uppercase**, otherwise it will raise syntax error. -After finishing adding this line, we use `ctrl + o` to save and press `ENTER` to overwrite, then we press `ctrl + x` to quit. +After adding this line, use `ctrl + o` to save and press `ENTER` to overwrite, then press `ctrl + x` to quit. ### Enable SSH for our new user -Next, we want to allow us to login as `johndoe` using SSH, and we may also want to disable login as `root` from SSH to make our server more secure. To do this, simply use the command: +Next, we want to allow us to login as `johndoe` using SSH, and we may also want to disable login as `root` from SSH to make our server more secure. To do this, use the command: ``` vi /etc/ssh/sshd_config @@ -147,11 +149,10 @@ PermitRootLogin yes Press `i` on your keyboard to enter insert mode and change the `yes` to `no` to disallow login as root. Then go to the bottom of the file and add the following lines: ``` -# You may add some description here AllowUsers johndoe ``` -Next, press `Esc` to quit insert mode, press `:` (column) to enable the command function and enter `wq` to write and quit. Finally, we use the command: +Next, press `Esc` to quit insert mode, press `:` (colon) to enable the command function and enter `wq` to write and quit. Finally, we use the command: ``` service sshd reload @@ -159,11 +160,16 @@ service sshd reload to enable our modifications. -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. +Now we've created a new user `johndoe` and enabled both its super user privilege and SSH access. Next, we'll be learning to link this user to our PostgreSQL database. ## Configuring Postgres -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. +Postgres allows from the start a user to access a database with its own name. Thus we must: + +1. Create a `johndoe` user inside PostgreSQL; and +2. Create a `johndoe` database in PostgreSQL. + +Because we have a `johndoe` user in our server, it will automatically have permission to access the `johndoe` user in Postgres, and will be able to access the `johndoe` database. ### Installing PostgreSQL @@ -180,7 +186,7 @@ sudo -i -u postgres createuser johndoe -P ``` -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. +After inputing and confirming the password, we now have created a Postgres user. Remember 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. ### Creating a PostgreSQL database for our user @@ -189,39 +195,37 @@ After having created the Postgres user, we use the command ``` createdb johndoe ``` - to create a database also name `johndoe`. And now we will explain the reason behind all these names. - - In Postgres, it allows a user to connect to the database with the same name by default, that is the Postgres `johndoe` user can always access the database named `johndoe`. And by default, Postgres only allows the unix user with the same name as its Postgres user to interact with it. - So now, our unix user `johndoe` can directly interact with the PostgreSQL database named `johndoe` using command +to create a database also name `johndoe`. Now, our UNIX user `johndoe` can directly interact with the PostgreSQL database named `johndoe` using the command: - ``` - psql - ``` +``` +psql +``` - Also, here are some useful Postgres commands: +### Some useful Postgres commands - To output the current connection info, use: +To output the current connection info, use: - ``` - \conninfo - ``` +``` +\conninfo +``` - To quit Postgres: +To quit Postgres: - ``` - \q - ``` +``` +\q +``` ### Improve security on our PostgreSQL database -However, we may notice that we've created a password for the Postgres user but never have to use it just because we used the same username in unix and Postgres. It is not really safe, so let's fix it. Use the below command to configure Postgres security options. +However, notice that we've created a password for the Postgres user but never have to use it just because we used the same username in UNIX and Postgres. It is safer to require a password. Use the below command to configure Postgres security options. ``` sudo vi /etc/postgresql/9.5/main/pg_hba.conf ``` Navigate to the bottom of the file, and we may see something like this: + ``` # Database administrative login by Unix domain socket local all postgres peer @@ -236,7 +240,7 @@ host all all 127.0.0.1/32 md5 host all all ::1/128 md5 ``` -We change the line +Change the line ``` local all all peer @@ -250,11 +254,11 @@ local all all md5 to enable password authentication. -*** important: *** SQLAlchemy will ***NOT*** work unless we do this modification. +**Important:** SQLAlchemy will ***NOT*** work unless we do this modification. ## Nginx -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/). +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 threads, and it performs very well so we don't need to worry about it slowing down our app. More details about nginx can be found [here](https://nginx.org/en/). ### Installing nginx @@ -277,15 +281,15 @@ sudo ufw add 'Nginx HTTP' sudo ufw add ssh ``` -***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! +**Important:** 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! -At last, if the UFW (Ubuntu Firewall) is inactive, use the command below to activate it: +If the UFW (Ubuntu Firewall) is inactive, use the command below to activate it: ``` sudo ufw enable ``` -And at last, if we want to check if nginx is running, we may use the command: +To check if nginx is running, use the command: ``` systemctl status nginx @@ -310,35 +314,34 @@ sudo vi /etc/nginx/sites-available/items-rest.conf Note that `items-rest` is what we named our service, you may change it accordingly, but remember to remain consistent throughout the configurations. -Next, we input the below text into `items-rest.conf` file. ***Remember to change your service name accordingly in this file as well*** +Next, we input the below text into `items-rest.conf` file. **Remember to change your service name accordingly in this file as well**. -``` +```nginx server { -listen 80; -real_ip_header X-Forwarded-For; -set_real_ip_from 127.0.0.1; -server_name localhost; - -location / { -include uwsgi_params; -uwsgi_pass unix:/var/www/html/items-rest/socket.sock; -uwsgi_modifier1 30; -} - -error_page 404 /404.html; -location = /404.html { -root /usr/share/nginx/html; -} - -error_page 500 502 503 504 /50x.html; -location = /50x.html { -root /usr/share/nginx/html; -} - + listen 80; + real_ip_header X-Forwarded-For; + set_real_ip_from 127.0.0.1; + server_name localhost; + + location / { + include uwsgi_params; + uwsgi_pass unix:/var/www/html/items-rest/socket.sock; + uwsgi_modifier1 30; + } + + error_page 404 /404.html; + location = /404.html { + root /usr/share/nginx/html; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } } ``` -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. +The above config allows nginx to send the request coming from our user's browser to our app. It also sets up some error pages for our service using nginx predefined pages. And at last, in order to enable our configuration, we need to do something like this: @@ -354,13 +357,13 @@ First, we create a folder for our app: sudo mkdir /var/www/html/items-rest ``` -Since the folder is owned by root user, and if we are using another user, we need to transfer ownership to our current user: +The folder is owned by the `root` user since we used `sudo` to create it. We need to transfer ownership to our current user: ``` sudo chown johndoe:johndoe /var/www/html/items-rest ``` -Remember that `johndoe` is the username in our tutorial, make sure you change it to yours accordingly. Same goes for `items-rest`. +Remember that `johndoe` is the username in our tutorial, make sure you change it to yours accordingly. The same goes for `items-rest`. Next, we get our app from Git: @@ -395,7 +398,7 @@ After it is installed, we can create a `virtualenv`: virtualenv venv --python==python3.5 ``` -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`. +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`. To activate `virtualenv`: @@ -403,7 +406,7 @@ To activate `virtualenv`: source venv/bin/activate ``` -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. +You should see `(venv)` appears at the start of your command line now. We assume that we are in `virtualenv` for all the following commands in this section unless specified otherwise. Next, use the command below to install the specified dependencies: @@ -411,10 +414,9 @@ Next, use the command below to install the specified dependencies: pip install -r requirements.txt ``` -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. - -And we will set up uWSGI in next section and finish deploying our app. +`requirement.txt` is a text file that includes all the dependencies that we created in our Git folder. It's highly recommended to have a `requirements.txt` file with all libraries your project requires. +Next, let's set up uWSGI and finish deploying our app. ## uWSGI @@ -458,7 +460,7 @@ The `ExecStart` property informs uWSGI on how to run our app as well as log it. At last, the `WantedBy` property in `Install` section allows the service to run as soon as the server boots up. -***important:*** Remember to change the username, password, database name and service name/folder accordingly in your own code. +**Important:** remember to change the username, password, database name and service name/folder accordingly in your own code. ``` [uwsgi]