Project 6 of the Udacity Full Stack Developer Nanodegree
hostname: ec2-18-191-144-56.us-east-2.compute.amazonaws.com
ip address: 18.191.144.56
Follow the default setup for a Ubuntu instance on AWS at https://lightsail.aws.amazon.com/
Upon completion, download the default .pem private key provided by Amazon on your Account Page, and use this to SSH login as ubuntu user.
Because we have just initialized a new machine in the cloud, it is safe to immediately update all packages on the OS. Do this by running the following:
sudo apt update
sudo apt upgrade
At this point, if the Ubuntu prompt states that a restart is required, run
sudo reboot
and then log back in from your host machine via ssh (remember to use the -i parameter with your .pem key)
Becase we are logged in as the Ubuntu user currently, we have access to sudo
and should use it at this point to create the grader
account. Run the following to create the grader
account as well as grant it sudo
access:
sudo adduser grader
I then verified this user creation by using finger
. First, I installed finger
by running
sudo apt install finger
and then I checked the grader user by running finger grader
and can confirm that a user account and a /home/grader
dir were created for the grader
user.
However, at this point, the grader
user does not sudo access yet. Run the following in the remote terminal:
sudo vim /etc/sudoers.d/grader
and press i
to enter insert
mode and type the following text:
grader ALL=(ALL) ALL
IMPORTANT: at this stage, make sure to exit the remote Ubuntu instance, and in your local host machine, run
ssh-keygen
to generate the public-private key pair for grader
.
Now that we have the key pairs, log back into the remote instance as ubuntu
user and as sudo
, run the following in the /home
directory:
sudo mkdir grader/.ssh
sudo touch grader/.ssh/authorized_keys
Now back on your local host machine, cat
the contents of the .pub
key that was created in the previous step and copy it to your clipboard. And over on your remote machine, using either nano
or vim
, sudo
edit the contents of authorized_keys
and paste the contents of the .pub
key from the local host machine. Save and close the file.
At this point, confirm that you can now login to the remote instance as grader
using the ssh -i
command and passing with it the file of the private key that was generated in the previous step.
At this stage, using the ubuntu
user again, log back into the remote instance if not already logged in, and run sudo vim /etc/ssh/sshd_config
.
Uncomment the "Port" line and change 22 to 2200. Uncomment the "PermitRootLogin" line and modify its parameter to "no." Lastly, ensure that the "PasswordAuthentication" line states "no" and if it does not, please change it to "no."
Save the file and run sudo service ssh restart
to ensure the changes are made effective.
ONE IMPORTANT STEP TO NOTE HERE: With Amazon Lightsail, we will also need to go to the "Networking" tab for our instance, and ensure that we create an account Firewall rule. Clikc on "Add another" and select "Custom" for Application, "TCP" for Protocol, and use "2200" as the Port range. Save the rule.
Now, we can exit the current SSH session and log back in but this time with the added parameter of -p 2200
and if everything was successful, we will be able to log back in as both ubuntu
and grader
users.
Log back in to the remote AWS instance and run the following:
sudo ufw allow 2200/tcp
sudo ufw allow www
sudo ufw allow ntp
After verifying that these are all entered correctly, only then proceed to run the next line:
sudo ufw enable
Press y
and Enter
when the confirmation dialog is presented.
Exit the SSH session and log back in to confirm that the rules are working and that UFW status is active.
Back in the remote instance, run:
sudo apt install apache2
sudo apt install git (if necessary)
sudo apt install libapache2-mod-wsgi
sudo apt install postgresql
Now that we have postgresql
installed, we will configure our database by running
sudo su - postgres
psql
Then enter the following commands, making sure that you are inside the postgresql shell:
CREATE USER catalog WITH PASSWORD 'password';
ALTER USER catalog CREATEDB;
CREATE DATABASE catalog WITH OWNER catalog;
\c catalog;
REVOKE ALL ON SCHEMA public FROM public;
GRANT ALL ON SCHEMA public TO catalog;
\q
exit
Back in the remote instance terminal, run the following:
sudo apt install python-pip
sudo pip install virtualenv
Now navigate to /var/www
and create a new directory called 'catalog'. Then navigate inside that folder by running cd catalog
and then run:
sudo git clone https://github.com/xr71/catalog-flask-app.git catalog
Then run the following:
sudo chown grader:grader catalog
cd catalog
touch catalog.wsgi
Edit the catalog.wsgi
file using either nano
or vim
and add the following:
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, "/var/www/catalog/")
from catalog import app as application
application.secret_key = 'SUPERSECRETKEY!'
Then save and exit the file.
Now, change the primary Flask file, a.k.a., app.py
, to __init__.py
by running mv app.py __init__.py
Edit __init__.py
such that you remove the following lines:
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
Now save, close (make sure you were in sudo) the file and make sure you navigate back to /var/www/catalog
.
Then run the following to create the right Python environment along with all the dependencies needed to run our Flask app:
sudo virtualenv venv
source venv/bin/activate
sudo chmod -R 777 venv
ls -al (to confirm venv and its all file permissions)
Now we can install flask and all the other dependencies needed to run our webapp:
pip install Flask httplib2 oauth2client sqlalchemy psycopg2 requests
Back inside our /var/www/catalog/catalog
directory, run sudo vim __init__.py
and modify the sqlalchemy engine by updating the driver resource to
engine = create_engine('postgresql://catalog:password@localhost/catalog')
and make sure to save, close the file.
very important: make sure to modify the contents of config.py
such that the client_secrets.json is read with an expicit path, like so:
CLIENT_ID = json.loads(open('/var/www/catalog/catalog/client_secrets.json', 'r').read())['web']['client_id']
Also, in order for Google OAuth to work, I needed to update my authorized domain and origin in the Google Cloud Console to include the hostname and ip address of my AWS Lightsail instance.
Now, create and modify our configuration file by running
sudo vim /etc/apache2/sites-available/catalog.conf
and pasting in the following contentns:
<VirtualHost *:80>
ServerName 18.191.144.56
ServerAlias ec2-18-191-144-56.us-east-2.compute.amazonaws.com
ServerAdmin admin@18.191.144.56
WSGIDaemonProcess catalog python-path=/var/www/catalog:/var/www/catalog/venv/lib/python2.7/site-packages
WSGIProcessGroup catalog
WSGIScriptAlias / /var/www/catalog/catalog.wsgi
<Directory /var/www/catalog/catalog/>
Order allow,deny
Allow from all
</Directory>
Alias /static /var/www/catalog/catalog/static
<Directory /var/www/catalog/catalog/static/>
Order allow,deny
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Save and exit the file.
Now, enable the virtual host by running sudo a2ensite catalog
followed by sudo service apache2 restart
.
http://flask.pocoo.org/docs/1.0/deploying/mod_wsgi/ https://stackoverflow.com/questions/4731364/internal-error-500-apache-but-nothing-in-the-logs