This is the last project of Udacity Full Stack Web Developer Nanodegree Program .
- Creation and installation of a linux server in the cloud environment.
- Setting up of this server to host a web application.
- Securing the server from a number of attack vectors.
- Installation and configuration of a database server to serve the web application.
- Deployment of the web application.
Application is live here
This project requires the student to create and set up linux server (e.g. Ubuntu) using the cloud services such as Google Cloud, Amazon AWS or DigitalOcean. The server should be then configured to host a web application while ensuring security, availability and accessibility of the server and the app. The server should:
- be initialized and available through a cloud environment.
- be made secure and remotely accessible through
SSH
- using the public-private key pair authentication feature instead of typical password protection. - have an account for the user
grader
withsudo
privileges. - let the user
grader
to log in to the server remotely throughSSH
using a public-private key pair authentication. - not allow remote logins for the root user.
- allow the incoming network traffic only for
SSH
on port 2200,HTTP
on port 80, andNTP
on port 123. - enforce the key-based authentication for the SSH.
- have all the packages up-to-date.
- have a database server set up and running for the web application.
- be set up to serve the Item Catalog Project as wsgi application.*
View more information about the project's requirements here.
I started initially with the Amazon Lightsail but soon found it somewhat restricting in terms of making the tweaks and availability of helpful resources. While Amazon EC2 provides somewhat more feature-rich and usable interface to set up, configure and run virtual machine or servers.
I created an Ubuntu 16.94 (Xenial) machine on EC2. These links (this guide and this tutorial proved quite helpful for setting up the instance.
IPv4 Public IP: 18.222.209.154
Public DNS (IPv4): ec2-18-222-209-154.us-east-2.compute.amazonaws.com
Accessible SSH Port: 2200
Application's URL: http://ec2-18-222-209-154.us-east-2.compute.amazonaws.com
- I used the Git SSH client and logged in using:
ssh -i "FullPathToTheFile\PrivateKey.pem" ubuntu@18.222.209.154
- Initially the instance was set up using the key-pair generated by the AWS services.
- I created a new key-pair on my PC locally using the
ssh-keygen
. - Updated the key pair such that the private key resides on my PC while the newly generated public key replaces the contents of the current one for the
ubuntu
user using:/home/ubuntu/.ssh/authorized_keys
. - Logged out and logged back in using the new key-pair.
All the packages were updated using:
sudo apt-get update
and thensudo apt-get upgrade
- Added the user
grader
using the commandsudo adduser grader
- Created the
/etc/sudoers.d
entry for thegrader
user usingsudo nano /etc/sudoers.d/grader
- Added the line
grader ALL=(ALL) NOPASSWD:ALL
to it - Set up SSH public key authorization for the user "grader" by following commands in order
mkdir /home/grader/.ssh
chown grader:grader /home/grader/.ssh
chmod 700 /home/grader/.ssh
cp /home/ubuntu/.ssh/authorized_keys /home/grader/.ssh/
chown grader:grader /home/grader/.ssh/authorized_keys
chmod 644 /home/grader/.ssh/authorized_keys
- Logged out as
ubuntu
and login back asgrader
usingssh -i "fullPathtoFile\LinuxServer.pem" grader@18.222.209.154
- Generated a separate key-pair for the user
grader
and replaced it with current version from/home/grader/.ssh/authorized_keys
- Checked if there is any error in using
sudo
for thegrader
user.
(P.S: You may or may not get the following warning: sudo: unable to resolve host "ip-SOME-IP". To fix this, the hostname was added to the loopback address in the /etc/hosts file so that the first line now reads: 127.0.0.1 localhost "ip-SOME-IP")
Updated the settings in /etc/ssh/sshd_config
as follows:
sudo nano /etc/ssh/sshd_config
to edit the file- modified the line
PermitRootLogin prohibit-password
toPermitRootLogin no
- uncommented the line
AuthorizedKeysFile %h/.ssh/authorized_keys
- ran
ssh restart
for the changes to take effect
Changed the port for SSH from 22 to 2200 in "/etc/ssh/sshd_config" as follows:
sudo nano /etc/ssh/sshd_config
to edit- modify the line
Port 22
to `Port 2200 ssh restart
for the changes to take effect
(Note: After the Port change of the server, the "inbound rules" for the "security group" of the server also needs to be updated from the console / AWS Dashboard. Changes should be made as:
- for the rule's "Type" value, change it from "SSH" to "Custom TCP Rule"
- change the value of "Port Range" from "22" to "2200"
- this may or may not result in changing/update of Public IP & DNS
- it's better option to reboot the server after this step)
Used following commands:
sudo ufw allow 2200/tcp
sudo ufw allow 80/tcp
or use sudo ufw allow www
sudo ufw allow 123/udp
sudo ufw enable
sudo ufw status verbose
(Note: Similar changing need to be made again from the console's "security group" tab as in the above step for each of the added firewall rules)
Modified the time zone to UTC using sudo timedatectl set-timezone UTC
The NTP daemon was installed to continuously adjust the system clock so no large differences in time develop. Installed with:
sudo apt-get install ntp
Installed Apache server and relevant library using:
sudo apt-get install libapache2-mod-wsgi
- Enabled mod_wsgi with
sudo a2enmod wsgi
- Started the web server with
sudo service apache2 start
sudo apt-get install apache2
Cloned the Item-Catalog-Project as www-user
- installed git:
sudo apt-get install git
- moved to srv:
cd /srv
- made the application directory:
sudo mkdir sports-bazar
sudo chown www-data:www-data sports-bazar/
- sudo -u www-data git clone https://github.com/abdullah-22/Item-Catalog-Project.git sports-bazar
Installed the Postgresql database engine
sudo apt-get install postgresql
- Checked if no remote connections are allowed by
sudo cat /etc/postgresql/9.5/main/pg_hba.conf
- Logged in as user "postgres" by
sudo su - postgres
- Got into postgreSQL shell by
psql
CREATE USER sportsbazar WITH PASSWORD 'password';
ALTER USER sportsbazar CREATEDB;
CREATE DATABASE sportsbazar WITH OWNER sportsbazar;
\c sportsbazar
REVOKE ALL ON SCHEMA public FROM public;
GRANT ALL ON SCHEMA public TO sportsbazar;
\q
exit
the postgres user
Created a new OAuth 2.0 client ID credentials for Google OUATH
- In Google Developer's consoloe
- set the javascript origin of the project to the IPv4 & Default DNS
- set the redirect_uris to
http://ec2-18-222-209-154.us-east-2.compute.amazonaws.com/gconnect
- downloaded the new credentials
- updated the credentials in the project in
g_client_secrets.json
& in/templates/login.html
- updated the
g_client_secrets
's path by appending/srv/path
to it in theauth.py
file (where needed) - updated the URL for the database in
app.py
&db_setup.py
toDB_URL = "postgresql://sportsbazar:password@localhost/sportsbazar"
- Add wsgi file as follows:
cd /srv/sports-bazar
sudo nano sportsbazar.wsgi
- added the following script:
#!/usr/bin/env python
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, '/srv/sport-sbazar/')
import random
import string
from sportsbazar import app as application
from sportsbazar.db_setup import db_create
from sportsbazar.db_populate import db_populate
application.config['DB_URL'] = "postgresql://sportsbazar:password@localhost/sportsbazar"
# Secret key to secure session and cookies
secret_key = "".join(random.choice(string.ascii_uppercase + string.digits) for x in xrange(32))
application.secret_key = secret_key
# Credentials of admin
application.config['ADMIN_ID'] = 2
application.config['ADMIN_NAME'] = "Abdullah A. Salman"
application.config['ADMIN_EMAIL'] = "abdullahahmadsalman22@gmail.com"
db_create(application.config['DB_URL'])
db_populate()
Using the following:
sudo apt-get install python-psycopg2 python-flask
sudo apt-get install python-sqlalchemy python-pip
sudo pip install oauth2client
sudo pip install requests
sudo pip install httplib2
Created the configuration file as: sudo nano /etc/apache2/sites-available/sportsbazar.conf
Added the following script to it:
<VirtualHost *:80>
ServerName 18.222.209.154
ServerAlias ec2-18-222-209-154.us-east-2.compute.amazonaws.com
ServerAdmin abdullahahmadsalman22@gmail.com
# Define WSGI parameters. The daemon process runs as the www-data user.
WSGIDaemonProcess sportsbazar user=www-data group=www-data threads=5
WSGIProcessGroup sportsbazar
WSGIApplicationGroup %{GLOBAL}
# Define the location of the app's WSGI file
WSGIScriptAlias / /srv/sports-bazar/sportsbazar.wsgi
# Allow Apache to serve the WSGI app from the catalog app directory
<Directory /srv/sports-bazar/>
Require all granted
</Directory>
# Setup the static directory (contains CSS, Javascript, etc.)
Alias /static /srv/sports-bazar/sportsbazar/static
# Allow Apache to serve the files from the static directory
<Directory /srv/sports-bazar/sportsbazar/static/>
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Ran the following commands in order:
sudo a2dissite 000-default.conf
sudo a2ensite sportsbazar.conf
sudo service apache2 reload
Hurrah! Application is now up & running!
(stuck at someplace? found any error? or just want to connect? see below :))
Abdullah A. Salman