Skip to content

Perfect for developers, system admins, and students who want to quickly set up a production-ready Linux environment on AWS.

Notifications You must be signed in to change notification settings

fix8developer/linux-server-configuration

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 

Repository files navigation

🐧 Linux Server Configuration

⚑ Overview

This project provides a complete guide and configuration scripts for setting up a secure Linux server on AWS EC2 . It walks through every step required to transform a fresh EC2 instance into a production-ready environment capable of hosting web applications.

The configuration covers:

  • πŸ” Security Hardening β†’ User management, SSH key authentication, firewall (UFW) setup, and disabling root login.
  • βš™οΈ Server Setup β†’ Package updates, timezone configuration, Apache2 + WSGI setup, PostgreSQL installation, and Python dependencies.
  • 🌐 Web Deployment β†’ Cloning a Flask application, configuring Apache Virtual Hosts for HTTP/HTTPS, enabling SSL, and setting up PostgreSQL for persistence.
  • πŸ›  Automation & Monitoring β†’ Essential commands, log checks, and configurations to keep the server stable and secure.

This repository is ideal for students, developers, and system administrators who want a ready-made reference for deploying Flask or other Python web apps on a hardened Linux environment with AWS EC2 .

πŸ›  Project Setup

πŸ–₯ Step 1: Create & Initiate the Instance


πŸ“¦ Step 2: First Update Packages


sudo apt-get update
sudo apt-get upgrade

πŸ”„ Step 3: Restart the Server


sudo reboot

πŸ‘€ Step 4: Add User "grader"


sudo adduser grader

Step 4.1: Set sudo Permissons For the New User "grader"

  • Create file in given directory with name "grader"

    sudo touch /etc/sudoers.d/grader
    sudo nano /etc/sudoers.d/grader
  • Type:

    grader ALL=(ALL) NOPASSWD:ALL
  • ctrl-o to save.

  • ctrl-x to exit.

πŸ”‘ Step 5: Login as User "grader"


sudo su grader

πŸ— Step 6: Generate an SSH Key


  • Generate an SSH Key on local Machine.

    ssh-keygen -t rsa -b 4096 -C <your_email@example.com>

    Note the filename and file location used (I used the default that was created at .ssh/id_rsa). When prompted, create a secure passphrase for your SSH key (do not share or document your passphrase).

πŸ“‹ Step 7: Copy Public Key


  • Make new directory after login to the "grader".

    sudo mkdir .ssh
  • Create file authorized_keys in .ssh directory.

    sudo touch .ssh/authorized_keys
  • Edit authorized_keys

    sudo nano .ssh/authorized_keys

Copy public key from local machine (.ssh/id_rsa.pub) and paste into .ssh/authorized_keys file on remote machine.

πŸ“ Step 8: Set File Permissions


sudo chmod 700 .ssh
sudo chmod 644 .ssh/authorized_keys

πŸ‘₯ Step 9: Set Owner and Group to User "grader"


sudo chown grader .ssh
sudo chgrp grader .ssh
sudo chown grader .ssh/authorized_keys
sudo chgrp grader .ssh/authorized_keys

♻️ Step 10: Restart SSH Service


sudo service ssh restart

🌐 Step 11: Access the Server Locally


  • So we can access the server locally by downloading the SSH key pairs provided inside AWS account

    ssh ubuntu@<public-ip> -i <key.pem> -p 2200
  • But now login as user "grader" locally

    ssh grader@<public-ip> -i .ssh/id_rsa -p 2200    

🚫 Step 12: Enforce Key-Based Authentication


sudo nano /etc/ssh/sshd_config
  • Change: PasswordAuthentication to no.
  • ctrl-o to save.
  • ctrl-x to exit.

πŸ”’ Step 13: Configure Firewall


  • Enter the following commands to configure defaults:

    sudo ufw default deny incoming
    sudo ufw default allow outgoing
  • Enter the following to allow/deny only specified ports:

    sudo ufw allow ssh
    sudo ufw allow 2200/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 123/udp
    sudo ufw allow 443/tcp
    sudo ufw deny 22/tcp
  • Before enable Firewall make sure port 22 is disabled:

    sudo nano /etc/ssh/sshd_config    
  • Open editor and change port number from 22 to 2200, set PermitRootLogin to no.

    sudo ufw enable
    sudo service ufw restart
    sudo ufw status

Note: If using Amazon EC2, you must configure both the AWS Security Groups (in the AWS console) and the server's UFW firewall to allow the same ports (e.g., 2200, 80, 443, 123) for proper connectivity.

πŸ•“ Step 14: Configure Linux Timezone to UTC


  • Open linux time zone configuration:

    sudo dpkg-reconfigure tzdata   
  • Navigate and Select None of the above

  • Navigate and Select UTC

βš™οΈ Step 15: Install Packages and Dependencies


sudo apt-get install git
sudo apt-get install python3-pip
sudo apt-get install apache2
sudo apt-get install libapache2-mod-wsgi-py3
sudo apt-get install postgresql
# (Recommended) Create and activate a Python virtual environment for your project:
python3 -m venv <venv-name>
source <venv-name>/bin/activate

# Upgrade pip and install Python dependencies inside the virtual environment:
pip install --upgrade pip
pip install flask
pip install SQLAlchemy
pip install oauth2client
pip install passlib
pip install requests
pip install psycopg2

When you are finished working on your project, you can deactivate the virtual environment:

deactivate

πŸ“‚ Step 16: Clone the Application Repository


  • Change the directory.

    cd /var/www
  • Inside that directory run:

    sudo git clone https://github.com/fix8developer/udacity-buid-an-item-catalog-application.git catalog    
  • Get inside the clone repository.

    cd /var/www/catalog    

πŸŒ€ Step 17: Create the WSGI File


  • Create new project.wsgi file inside the downloaded repository which will serve my flask application.

    sudo touch /var/www/catalog/project.wsgi
    sudo nano /var/www/catalog/project.wsgi   
  • Add the following content

    import sys
    sys.path.insert(0, "/var/www/catalog")
    
    from project import app as application

    "from project" phrase is actually the name of my main python file.

πŸ— Step 18: Configure Apache


🌍 Step 18.1: Creating New HTTP Configuration File

sudo touch /etc/apache2/sites-available/catalog.conf
sudo nano /etc/apache2/sites-available/catalog.conf    
  • Add the following content:

    <VirtualHost *:80>
        ServerName <public-ip/localhost>
        ServerAdmin kashifiqbal23@gmail.com
    
        WSGIScriptAlias / /var/www/catalog/project.wsgi
    
        <Directory /var/www/catalog>
            Require all granted
            WSGIApplicationGroup %{GLOBAL}
            WSGIScriptReloading On
        </Directory>
    
        ErrorLog ${APACHE_LOG_DIR}/catalog_error.log
        CustomLog ${APACHE_LOG_DIR}/catalog_access.log combined
    </VirtualHost>

πŸ” Step 18.2: Creating New HTTPS Configuration File

sudo touch /etc/apache2/sites-available/catalog-ssl.conf
sudo nano /etc/apache2/sites-available/catalog-ssl.conf    
  • Add the following content

    <IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName <public-ip/localhost>
        ServerAdmin fix8developer@gmail.com
    
        WSGIScriptAlias / /var/www/catalog/project.wsgi
    
        <Directory /var/www/catalog>
            Require all granted
            WSGIApplicationGroup %{GLOBAL}
            WSGIScriptReloading On
        </Directory>
    
        SSLEngine on
        SSLCertificateFile /etc/ssl/certs/selfsigned.crt
        SSLCertificateKeyFile /etc/ssl/private/selfsigned.key
    
        ErrorLog ${APACHE_LOG_DIR}/catalog_ssl_error.log
        CustomLog ${APACHE_LOG_DIR}/catalog_ssl_access.log combined
    </VirtualHost>
    </IfModule>

β†ͺ️ Step 18.3: Redirect HTTP to HTTPS (Optional)

sudo nano /etc/apache2/sites-available/catalog.conf    
  • Content

    <VirtualHost *:80>
        ServerName <public-ip/localhost>
        Redirect permanent / https://<public-ip/localhost>/
    </VirtualHost>

πŸ” Step 19: Create Your Own Self-Signed SSL Certificate


Step 19.1: Install OpenSSL

sudo apt-get update
sudo apt-get install -y openssl

Step 19.2: Create a Private Key

openssl genrsa -out selfsigned.key 2048

Step 19.3: Generate a Certificate Signing Request (CSR)

openssl req -new -key selfsigned.key -out selfsigned.csr

Common Name should be your domain (or public IP if no domain).

Step 19.4: Generate a Self-Signed SSL Certificate

openssl x509 -req -days 365 -in selfsigned.csr -signkey selfsigned.key -out selfsigned.crt

This creates selfsigned.crt (certificate) valid for 1 year.

Step 19.5: Copy SSL Files to Secure Location

sudo cp selfsigned.crt /etc/ssl/certs/
sudo cp selfsigned.key /etc/ssl/private/

Set proper permissions:

sudo chmod 600 /etc/ssl/private/selfsigned.key

βœ… Step 20: Enable the Application Site


Disable the default Apache site and enable your flask app.

  • Disable the default configuration file:

    sudo a2dissite 000-default.conf    
  • Enable the catalog.conf (Flask app configuration for HTTP):

    sudo a2ensite catalog.conf
    sudo a2enmod wsgi
  • Enable the catalog-ssl.conf (Flask app configuration for HTTPS):

    sudo a2enmod ssl
    sudo a2ensite catalog-ssl.conf    
  • To active the new configuration we need to run:

    sudo systemctl reload apache2

✏️ Step 21: Modify the Cloned Application


If the application was cloned from (build-an-item-catalog-application), the following modifications are required:

  • Edit the project.py file and move the app.secret_key out of ...

    if __name__ == '__main__':
        app.secret_key = 'super_secret_key'
        app.run()

    -- by moving it to the following line:

    app = Flask(__name__)
    app.secret_key = 'super_secret_key'
  • Also update the path to client_secrets.json in project.py to use the absolute file path (e.g., /var/www/catalog/client_secrets.json), since the working directory on the remote machine is different from your local machine.

    CLIENT_ID = json.loads(
        open('client_secrets.json', 'r').read())['web']['client_id']

    -- to this form:

    CLIENT_ID = json.loads(
        open('/var/www/catalog/client_secrets.json', 'r').read())['web']['client_id']

🐘 Step 22: Use PostgreSQL Instead of SQLite


Edit project.py, database_setup.py in clone repository to use postgresql database instead of sqlite

# engine = create_engine('sqlite:///catalog.db')
engine = create_engine(
    'postgresql+psycopg2://catalog:catalog@localhost/catalog')

πŸ—„ Step 23: Configure the Database


Create database user "catalog"

sudo -u postgres psql postgres    
CREATE DATABASE catalog;
CREATE USER catalog;
ALTER ROLE catalog with PASSWORD 'catalog';
GRANT ALL PRIVILEGES ON DATABASE catalog TO catalog;
\q

πŸ“œ Step 24: Check Server Logs


To view server side error for HTTP:

sudo tail -n 30 /var/log/apache2/catalog_error.log

To view server side error for HTTPS:

sudo tail -n 30 /var/log/apache2/catalog_ssl_error.log

To view server side error for ALL:

sudo tail /var/log/apache2/error.log    

πŸš€ Run the Project

πŸ–Ό Expected Output

Build an Item Catalog Application on Configured Linux Server

πŸ“– Resources

πŸ“œ License

Linux Server Configuration is Copyright ©️ 2025 Kashif Iqbal. It is free, and may be redistributed under the terms specified in the LICENSE file.

About

Perfect for developers, system admins, and students who want to quickly set up a production-ready Linux environment on AWS.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published