IP ADDRESS: 35.176.196.186 HTTP ALIAS ADDRESS: 35.176.196.186.xip.io SSH Port: 2200
Take a baseline installation of a Linux server and prepare it to host web applications. To secure the server from a number of attack vectors, install & configure a database server, & deploy an existing web application onto it.
- Start a new Ubuntu Linux server instance on Amazon Lightsail.
- Log in or Sign up to AWS.
- Click on Create instance.
- Instance location:
- You can change AWS Region or leave the default selected.
- Pick your instance image:
- Select a platform - Linux/Unix
- Select a blueprint - OS Only & Ubuntu 18.04 LTS
- Choose your instance plan - Lowest tier (First month free!)
- Identify your instance:
- You can change the hostname or leave the default selected.
- Click on Create instance.
- The new instance will appear, then click on it.
- Take note of the Public IP: 35.176.196.186 & Username: ubuntu
Learn more about instances
You can click on the Connect using SSH button to connect to the instance, however we will set up a private key to connect using our local machine.
Following from the previous section:
- Scroll to the bottom, where the last sentence reads:
You can download your default private key from the Account page - Click on Account page.
- Manage your SSH keys:
- Click on the Download link of your AWS Region.
- Save the file in your Downloads folder.
- Open the terminal
Alt + Ctrl + T. - Check you are in your home directory:
$ pwd- This should print
/home/{your-username}
- This should print
- Move the downloaded file
LightsailDefaultKey-{AWS Region}.pemfromDownloadsdirectory into.sshdirectory & rename itubuntu_motorbike_catalog.rsa:
$ mv -v Downloads/LightsailDefaultKey-{AWS Region}.pem .ssh/ubuntu_motorbike_catalog.rsa - Change the file permissions so only the owner can read & write:
$ chmod -v 600 .ssh/ubuntu_motorbike_catalog.rsa - To SSH into the instance server using the Public IP & Username:
$ ssh -i .ssh/ubuntu_motorbike_catalog.rsa ubuntu@35.176.196.186- The terminal will output some info about the instance server & the prompt will change to
ubuntu@ip-{private-ip}:~$, this means you are successfully connected to the Amazon Lightsail instance server.
- The terminal will output some info about the instance server & the prompt will change to
Following from the previous section:
- Update all currently installed packages on the instance server through the SSH connection in your terminal, run the following commands:
$ sudo apt update
NOTE: To view the upgradable packages, run the command$ apt list --upgradable
$ sudo apt upgrade
NOTE: In the terminal a message about restarting services during package upgrades: select Yes NOTE: In the terminal a message about configuring openssh-server: select install the package maintainer's version NOTE: In the terminal a message about grub menu: select install the package maintainer's version$ exit - Reboot the instance server:
- Click on the instance server & then click Reboot.
- SSH back into the instance server:
$ ssh -i .ssh/ubuntu_motorbike_catalog.rsa ubuntu@35.176.196.186 - Change the SSH port from 22 to 2200:
- Edit the
/etc/ssh/sshd_configfile$ sudo nano /etc/ssh/sshd_config - Search for
#Port 22& change toPort 2200. - Save the file
Ctrl + O, then press Enter. - Exit nano,
Ctrl + X - Restart SSH service
$ sudo service ssh restart
Learn more about nano
- Edit the
- Configure the Uncomplicated Firewall (UFW) to only allow incoming connections for SSH (port 2200), HTTP (port 80), & NTP (port 123):
- Check the status of UFW:
$ sudo ufw status verboseor$ sudo ufw status - Define default rules for allowing & denying connections:
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing - Allow connection on port 2200 (SSH) using TCP:
$ sudo ufw allow 2200/tcp - Deny connection on port 22 (SSH) using TCP:
$ sudo ufw deny 22/tcpor$ sudo ufw deny ssh - Allow connection on port 80 (HTTP) using TCP:
$ sudo ufw allow 80/tcpor$ sudo ufw allow www - Allow connection on port 123 (NTP) using UDP:
$ sudo ufw allow 123/udpor$ sudo ufw allow ntp - Check added user rules
$ sudo ufw show added - Activate UFW
$ sudo ufw enable - Close the SSH connection
$ exit
Source: DigitalOcean
- Check the status of UFW:
- Update firewall to match changes on Amazon Lightsail instance server:
- On the instance server, click on the three vertical dots & click on Manage.
- Click the Networking tab.
- Scroll down to Firewall section & click on Add another.
- Update the rules to match the rules applied above.
- Scroll back to the top & click on Reboot.
NOTE: From this point forward, to SSH into the instance server, run the command:
$ ssh -i .ssh/ubuntu_motorbike_catalog.rsa -p 2200 ubuntu@35.176.196.186
- Test the above command.
Allow the grader to log in to the server with sudo privileges.
- Create a new user account named grader:
$ sudo adduser grader- Enter a password for the new user. Password:
grader - Press Enter for default information.
- Enter a password for the new user. Password:
- Give grader the permission to
sudo:- Open a file
sudoers.tmpwith the command$ sudo visudo - Find the comment
# User privilege specification& underroot, add the followinggrader ALL=(ALL:ALL) ALL - Save the file
Ctrl + O, then press Enter. - Exit nano,
Ctrl + X
- Open a file
- Create a SSH key pair for grader using the
ssh-keygentool:- Keep the current terminal open.
- Open a new terminal
Alt + Ctrl + T, this will be the local machine. - Run the command
$ ssh-keygen, save file to/home/{your-username}/.ssh/grader_key& press Enter if prompted for passphrase. - List new files created
$ ls -a .ssh/ - Copy contents of file from terminal
$ cat .ssh/grader_key.pub - Switch back to the other terminal with the SSH connection:
- Login as grader
$ su - grader - Check if there is a
.sshdirectory$ ls -a - Create
.sshdirectory$ mkdir .ssh - Create
authorized_keysfile in.sshdirectory$ touch .ssh/authorized_keys - Paste contents of
grader_key.pubfile intoauthorized_keysfile$ nano .ssh/authorized_keys - Save the file
Ctrl + O, then press Enter. - Exit nano,
Ctrl + X - Change
.sshfolder permissionchmod -v 700 .ssh/ - Change
authorized_keysfile permissionchmod -v 644 .ssh/authorized_keys - Force key based authentication:
- Edit the
/etc/ssh/sshd_configfile$ sudo nano /etc/ssh/sshd_config - Search for
#PasswordAuthentication yes& change toPasswordAuthentication no
- Edit the
- Disable remote root login:
- Search for
#PermitRootLogin prohibit-password& change toPermitRootLogin no - Save the file
Ctrl + O, then press Enter. - Exit nano,
Ctrl + X
- Search for
- Restart SSH service
$ sudo service ssh restart - Logout as grader
$ exit - Close the SSH connection
$ exit
NOTE: You can now SSH into the instance server as grader, run the command:
$ ssh -i .ssh/grader_key -p 2200 grader@35.176.196.186
- Login as grader
- Test the above command.
- Configure the local timezone to UTC:
$ sudo dpkg-reconfigure tzdata- Select None of the above.
- Select UTC.
NOTE: To check the timezone
$ date +%Z
- Install & configure Apache to serve a Python 3 mod_wsgi application:
- Install Apache
$ sudo apt install apache2 - Test Apache installation:
- Open a Browser & enter the Public IP address
http://35.176.196.186
- Open a Browser & enter the Public IP address
- Install mod_wsgi for Python 3
$ sudo apt install python3-setuptools python3-dev libapache2-mod-wsgi-py3 - Restart Apache
$ sudo service apache2 restart
- Install Apache
- Install Python 3 pip & venv:
$ sudo apt install python3-pip python3-venv - Install & configure PostgreSQL:
$ sudo apt install postgresql postgresql-contrib libpq-dev- Do not allow remote connections
$ sudo nano /etc/postgresql/10/main/pg_hba.conf - Only connections from localhost are allowed.
- Do not allow remote connections
- Create a new database user named catalog that has limited permissions to the catalog application database:
- Login to PostgreSQL as postgres
$ sudo -u postgres psql - Create user
# CREATE USER catalog WITH PASSWORD 'catalog'; - Allow user to create databases
# ALTER USER catalog CREATEDB; - Create the database
# CREATE DATABASE catalog WITH OWNER catalog; - Connect to database
# \c catalog - Only allow user catalog permission to database
# GRANT ALL PRIVILEGES ON DATABASE catalog TO catalog; - Quit PostgreSQL
# \q
- Login to PostgreSQL as postgres
- Install git:
sudo apt install git- It was already installed
The project to be deployed will be Motorbike Catalog
- Clone & setup the Item Catalog project from the Github repository:
- Move to Apache root folder
$ cd /var/www/ - Clone project repo
$ sudo git clone https://github.com/biobot-01/motorbike-catalog.git - Change ownership of project folder
$ sudo chown -vR grader:grader motorbike-catalog - Rename
motorbike-catalogdirectory$ sudo mv -v motorbike-catalog/ MotorbikeCatalog - Move into
MotorbikeCatalogdirectory$ cd MotorbikeCatalog - Rename
catalogdirectory$ mv -v catalog/ MotorbikeCatalog - Move
database_setup.pyfile into innerMotorbikeCatalog$ mv -v database_setup.py MotorbikeCatalog/ - Move to the inner
MotorbikeCatalogdirectory$ cd MotorbikeCatalog/ - Rename
app.pyto__init__.py$ mv -v app.py __init__.py - Edit
__init__.py,models.py,database_setup.py& changeengine = create_engine('sqlite:///motorbike_catalog.db')toengine = create_engine('postgresql://catalog:catalog@localhost/catalog') - Edit
database_setup.py& changefrom catalog.modelstofrom MotorbikeCatalog.models - Edit
__init__.py& change
tofrom models import ... app.secret_key = 'super_secret_key' app.debug = True app.run(host='127.0.0.1', port=8000, threaded=False)from MotorbikeCatalog.models import ... app.run()- Edit
__init__.py& change all file paths to absolute paths.
- Move to Apache root folder
- Configure wsgi file:
- Return to outer
MotorbikeCatalogdirectorycd ../ - Create a new file
app.wsgitouch app.wsgi - Edit
app.wsgi& add
#!/usr/bin/env python3 import sys import site import logging python_home = '/var/www/MotorbikeCatalog/MotorbikeCatalog/venv/flask' # Calculate path to site-packages directory python_version = '.'.join(map(str, sys.version_info[:2])) site_packages = python_home + '/lib/python{}/site-packages'.format(python_version) # Add the site-packages directory site.addsitedir(site_packages) logging.basicConfig(stream=sys.stderr) sys.path.insert(0, '/var/www/MotorbikeCatalog') from secrets import token_hex from MotorbikeCatalog import app as application application.secret_key = token_hex(32)
- Return to outer
- Setup Python virtual environment with python3-venv:
- Move to the inner
MotorbikeCatalogdirectory$ cd MotorbikeCatalog/ - Create folder
$ mkdir venv - Create venv
$ python3 -m venv venv/flask&$ python3 -m venv venv/python - Activate
venv/flaskwith$ source venv/flask/bin/activate - Update pip
$ pip install -U pip - Install requirements
$ pip install -r requirements.txt - Install psycopg2
$ pip install psycopg2 - Create the database schema
$ python models.py - Deactivate venv
$ deactivate
- Move to the inner
- Set it up in the server so that it functions correctly when visiting the server's IP address in a browser:
$ cd /etc/apache2/- Configure virtual host:
- Copy vhost file
$ sudo cp -v sites-available/000-default.conf sites-available/001-motorbikecatalog.conf - Edit
001-motorbikecatalog.conf$ sudo nano sites-available/001-motorbikecatalog.conf& add
<VirtualHost *:80> ServerName 35.176.196.186 ServerAlias 35.176.196.186.xip.io ServerAdmin webmaster@localhost DocumentRoot /var/www/MotorbikeCatalog ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined WSGIDaemonProcess MotorbikeCatalog python-home=/var/www/MotorbikeCatalog/MotorbikeCatalog/venv/python user=grader group=grader threads=5 WSGIScriptAlias / /var/www/MotorbikeCatalog/app.wsgi <Directory /var/www/MotorbikeCatalog/MotorbikeCatalog> WSGIProcessGroup MotorbikeCatalog WSGIApplicationGroup %{GLOBAL} Require all granted </Directory> Alias /static /var/www/MotorbikeCatalog/MotorbikeCatalog/static <Directory /var/www/MotorbikeCatalog/MotorbikeCatalog/static> Require all granted </Directory> </VirtualHost>- Disable default vhost
$ sudo a2dissite 000-default.conf - Enable motorbikecatalog vhost
$ sudo a2ensite 001-motorbikecatalog.conf - Restart Apache seerver
$ sudo service apache2 restart
Source: DigitalOcean
- Copy vhost file
- Configure virtual host:
- Make sure that the
.gitdirectory is not publicly accessible via the browser:- Change to
apache2directory$ cd /etc/apache2/ - Edit
security.conffile$ sudo nano conf-available/security.conf& changeServerTokens OStoServerTokens Prod,ServerSignature ontoServerSignature off& add
<DirectoryMatch "/\.git"> Require all denied </DirectoryMatch>- Restart Apache
$ sudo service apache2 restart
- Change to
Thanks to Daniel A (jungleBadger) for pointing me to his project