This was originally an assigned project from Udacity’s full-stack nanodegree program. It seemed complicated enough to deserve a post documenting the steps taken. I hope you enjoy setting it up from scratch as much I did!

Tasks given and method for completion:

  • Launch your Virtual Machine with your Udacity account
    • Must be logged into your Udacity account.
    • Visit this link and press Create Development Environment.
  • Follow the instructions provided to SSH into your server
    • Download private key
    • Move the private key file into the folder ~/.ssh (where ~ is your environment’s home directory). So if you downloaded the file to the Downloads folder, just execute the following command in your terminal. mv ~/Downloads/udacity_key.rsa ~/.ssh/
    • Open your terminal and type in chmod 600 ~/.ssh/udacity_key.rsa
    • In your terminal, type in ssh -i ~/.ssh/udacity_key.rsa root@
  • Create a new user named grader
    • sudo adduser grader
    • optional: install finger to check user has been added apt-get install finger
    • finger grader
  • Give the grader the permission to sudo
    • The README file in the /etc/sudoers.d says:”please note that using the visudo command is the recommended way to update sudoers content, since it protects against many failure modes.” so that’s what we will do!
    • sudo visudo
    • inside the file add grader ALL=(ALL:ALL) ALL below the root user under “#User privilege specification”
    • save file(nano: ctrl+x, Y, Enter)
  • Update all currently installed packages
    • Find updates:sudo apt-get update
    • Install updates:sudo sudo apt-get upgrade Hit Y for yes and give yourself a break while it installs.
  • Change the SSH port from 22 to 2200 and other SSH configuration required from grading rubic
    • nano /etc/ssh/sshd_config change port 22 to port 2200
    • while in the file also change PermitRootLogin without-password to PermitRootLogin no to disallow root login
    • Change PasswordAuthentication from no to yes. We will change back after finishing SHH login setup
    • append AllowUsers grader inside file to allow grade to login through SSH
    • save file(nano: ctrl+x, Y, Enter)
    • restart ssh servicesudo service ssh reload
  • Create SSH keys and copy to server manually:
    • On your local machine generate SSH key pair with: ssh-keygen
    • save youkeygen file in your ssh directory /Users/username/.ssh/ example full file path that could be used: /Users/username/.ssh/project5
    • You can add a password to use encase your keygen file gets compromised(you will be prompted to enter this password when you connect with key pair)
    • login into grader account using password set during user creation ssh -v grader@*Public-IP-Address* -p 2200
    • Make .ssh directorymkdir .ssh
    • make file to store keytouch .ssh/authorized_keys
    • On your local machine read contents of the public key cat .ssh/
    • Copy the key and paste in the file you just created in grader nano .ssh/authorized_keys paste contents(ctr+v)
    • save file(nano: ctrl+x, Y, Enter)
    • Set permissions for files: chmod 700 .ssh chmod 644 .ssh/authorized_keys
    • Change PasswordAuthentication from yes back to no. nano /etc/ssh/sshd_config
    • save file(nano: ctrl+x, Y, Enter)
    • login with key pair: ssh grader@Public-IP-Address* -p 2200 -i ~/.ssh/project5

    • alternatively you can use a shorter method found here
  • Configure the Uncomplicated Firewall (UFW) to only allow incoming connections for SSH (port 2200), HTTP (port 80), and NTP (port 123)
    • Check UFW status to make sure its inactivesudo ufw status
    • Deny all incoming by defaultsudo ufw default deny incoming
    • Allow outgoing by defaultsudo ufw default allow outgoing
    • Allow SSH on port 2200sudo ufw allow 2200/tcp
    • Allow HTTP on port 80sudo ufw allow 80/tcp
    • Allow NTP on port 123sudo ufw allow 123/udp
    • Turn on firewallsudo ufw enable
  • Configure the local timezone to UTC
    • run sudo dpkg-reconfigure tzdata from prompt: select none of the above. Then select UTC.
  • Install and configure Apache to serve a Python mod_wsgi application
    • sudo apt-get install apache2 Check if “It works!” at you public IP address given during setup.
    • install mod_wsgi: sudo apt-get install libapache2-mod-wsgi
    • configure Apache to handle requests using the WSGI module sudo nano /etc/apache2/sites-enabled/000-default.conf
    • add WSGIScriptAlias / /var/www/html/myapp.wsgi before </ VirtualHost> closing line
    • save file(nano: ctrl+x, Y, Enter)
    • Restart Apache sudo apache2ctl restart
  • Install git, clone and setup your Catalog App project (from your GitHub repository from earlier in the Nanodegree program) so that it functions correctly when visiting your server’s IP address in a browser. Remember to set this up appropriately so that your .git directory is not publicly accessible via a browser!

  • install git
    • sudo apt-get install git
    • git config --global "YOURNAME"
    • git config --global ""
  • install python dev and verify WSGI is enabled
    • Install python-dev packagesudo apt-get install python-dev
    • Verify wsgi is enabled sudo a2enmod wsgi
  • Create flask app taken from digitalocean
    • cd /var/www
    • sudo mkdir catalog
    • cd catalog
    • sudo mkdir catalog
    • cd catalog
    • sudo mkdir static templates
    • sudo nano
       from flask import Flask
      app = Flask(__name__)
      def hello():
          return "Hello, world (Testing!)"
      if __name__ == "__main__":
  • install flask
    • sudo apt-get install python-pip
    • sudo pip install virtualenv
    • sudo virtualenv venv
    • sudo chmod -R 777 venv
    • source venv/bin/activate
    • pip install Flask
    • python
    • deactivate
  • Configure And Enable New Virtual Host
    • Create host config file sudo nano /etc/apache2/sites-available/catalog.conf
    • paste the following:
      <VirtualHost *:80>
        ServerAdmin admin@
        WSGIScriptAlias / /var/www/catalog/catalog.wsgi
        <Directory /var/www/catalog/catalog/>
            Order allow,deny
            Allow from all
        Alias /static /var/www/catalog/catalog/static
        <Directory /var/www/catalog/catalog/static/>
            Order allow,deny
            Allow from all
        ErrorLog ${APACHE_LOG_DIR}/error.log
        LogLevel warn
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    • save file(nano: ctrl+x, Y, Enter)
    • Enable sudo a2ensite catalog
  • Create the wsgi file
    • cd /var/www/catalog
    • sudo nano catalog.wsgi
    import sys
    import logging
    from catalog import app as application
    application.secret_key = 'Add your secret key'
    • save file(nano: ctrl+x, Y, Enter)

    • sudo service apache2 restart

  • Clone Github Repo
    • sudo git clone
    • make sure you get hidden files iin move shopt -s dotglob. Move files from clone directory to catalog mv /var/www/catalog/devpost/* /var/www/catalog/catalog/
    • remove clone directory sudo rm -r devpost
  • make .git inaccessible
    • from cd /var/www/catalog/ create .htaccess file sudo nano .htaccess
    • paste in RedirectMatch 404 /\.git
    • save file(nano: ctrl+x, Y, Enter)
  • install dependencies:
    • source venv/bin/activate
    • pip install httplib2
    • pip install requests
    • sudo pip install --upgrade oauth2client
    • sudo pip install sqlalchemy
    • pip install Flask-SQLAlchemy
    • sudo pip install python-psycopg2
    • If you used any other packages in your project be sure to install those as well.
  • Install and configure PostgreSQL:
    • Install postgressudo apt-get install postgresql
    • install additional modelssudo apt-get install postgresql-contrib
    • by default no remote connections are not allowed
    • config sudo nano
    • python engine = create_engine('postgresql://catalog:db-password@localhost/catalog')
    • repeat for
    • copy your main file into the file mv
    • Add catalog user sudo adduser catalog
    • login as postgres super usersudo su - postgres
    • enter postgrespsql
    • Create user catalogCREATE USER catalog WITH PASSWORD 'db-password';
    • Change role of user catalog to creatDB ALTER USER catalog CREATEDB;
    • List all users and roles to verify\du
    • Create new DB “catalog” with own of catalogCREATE DATABASE catalog WITH OWNER catalog;
    • Connect to database\c catalog
    • Revoke all rights REVOKE ALL ON SCHEMA public FROM public;
    • Give accessto only catalog roleGRANT ALL ON SCHEMA public TO catalog;
    • Quit postgres\q
    • logout from postgres super userexit
    • Setup your database schema python

    • I had problems importing psycopg2 this stack overflow post helped me
    • retstart apache sudo service apache2 restart

    • I was getting a No such file or directory: 'client_secrets.json' error. I fixed using a raw path to the file open(r'/var/www/catalog/catalog/client_secrets.json', 'r').read())... You’ll also need to do this for any other instances of the file path stack overflow
  • fix OAuth to work with hosted Application * Google wont allow the IP address to make redirects so we need to set up the host name address to be usable.
    • go to to get your host name by entering your public IP address Udacity gave you.
    • open apache configbfile sudo nano /etc/apache2/sites-available/catalog.conf
    • below the ServerAdmin paste ServerAlias YOURHOSTNAME
    • make sure the virtual host is enabled sudo a2ensite catalog
    • restart apache server sudo service apache2 restart
    • in your google developer console add your host name and IP address to Authorized Javascript origins. And add YOURHOSTNAME/ouath2callback to the Authorized redirect URIs.
    • Note that it may take a few minutes for you to see changes, so if you still can’t login right away don’t panic!

Exceeds specs requirements

  • Install glances for monitoring (Exceeds specs requirement)
    • install glances sudo pip install Glances
    • run glances to see monitor
  • Configure firewall to monitor for unsuccessful attempts and use cron scripts to automatically manage packages (Exceeds specs requirement)

    • install fail2band sudo apt-get install fail2ban
    • copy config file to .local sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
    • open .local config file to set parameters sudo nano /etc/fail2ban/jail.local Make at least the following changes. You can change bantime or other settings as well. This will allow email with log info and set SSH to the correct port.
    destemail = YOURNAME@DOMAIN
    action = %(action_mwl)s
    under [ssh] change port = 2220
    • install sendmailsudo apt-get install nginx sendmail
    • stop service sudo service fail2ban stop
    • Start service sudo service fail2ban start

    • install unattended-upgrades sudo apt-get install unattended-upgrades
    • enable sudo dpkg-reconfigure -plow unattended-upgrades
    • Automatically install security updates

Sources used:

Configuring Linux Web Servers -

Get rid of sudo error message - askubuntu

Create new ssh user - askubuntu

More info on UFW - Ubuntu docs

Change timezone - Ubuntu docs

Flask App on Ubuntu VPS - DigitalOcean

python packages not installing in virtualenv using pip - stackoverflow

Move files from one directtory to another - stack exchange

Make .git directory web inaccessible

Fix google + Oauth issue - Udacity Forum

Using glances - Glances docs

Use fail2ban to monitor login - digital ocean

Python 2 in virtual enviroment

unattended upgardes - ubuntu docs

Using postgres in flask

If you have any questions about this post or want to stay connected find me at:

Email Github Twitter LinkedIn