A Flask-based URL shortener service with Redis backend, deployed on AWS EC2 with automatic SSL certificate management.
Authors: Jake Morro, Cole Aydelotte
Development process described in developers.md
- AWS EC2 instance (Amazon Linux 2 recommended)
- Security group configured with the following inbound rules:
- Port 22 (SSH)
- Port 80 (HTTP)
- Port 443 (HTTPS)
- SSH access to your EC2 instance
- Your DNS registration token from the course
SSH into your EC2 instance:
ssh -i your-key.pem ec2-user@your-ec2-ip-addressCopy and paste the entire up.sh script into your terminal:
sudo yum -y install git
git clone https://github.com/cs298f25/URL-Shortener.git
cd URL-Shortener
echo USERNAME=yourusername
echo LABEL=web
echo TOKEN=your-bearer-token-here
nano .env
./register_ip.sh
./ec2_deploy.shWhen the nano .env command opens the editor, replace the placeholder values:
USERNAME=yourusername
LABEL=web
TOKEN=your-bearer-token-here
Replace:
yourusernamewith your actual usernameyour-bearer-token-herewith your DNS registration token
Save and exit nano (Ctrl+X, then Y, then Enter).
Before running ./ec2_deploy.sh, you need to edit the SUBDOMAIN variable:
nano ec2_deploy.shFind the line:
SUBDOMAIN="aydelottecweb"Change it to match your username and label (e.g., if USERNAME=jsmith and LABEL=web, use "jsmithweb").
Save and exit (Ctrl+X, then Y, then Enter).
The scripts will automatically:
- Register your EC2 IP address with the DNS service
- Install and configure Redis
- Set up Python virtual environment and dependencies
- Generate SSL certificates using Let's Encrypt
- Deploy and start the Flask application
During SSL certificate generation, you'll be prompted for:
- Your email address
- Agreement to Let's Encrypt Terms of Service
- Redis 6: In-memory data store for URL mappings
- Flask Application: Web service running on HTTPS
- SSL Certificate: Automatic HTTPS via Let's Encrypt
- Systemd Services: Automatic startup on reboot
After successful deployment, your URL shortener will be available at:
https://[username][label].moraviancs.click
For example: https://jsmithweb.moraviancs.click
# View Flask application logs
sudo journalctl -u flask -f
# View Redis logs
sudo journalctl -u redis6 -f
# Restart Flask service
sudo systemctl restart flask
# Restart Redis service
sudo systemctl restart redis6
# Check service status
sudo systemctl status flask
sudo systemctl status redis6# Renew SSL certificate
sudo certbot renew
# Test certificate renewal
sudo certbot renew --dry-runIf you get errors about ports being in use, check what's running:
sudo netstat -tulpn | grep :80
sudo netstat -tulpn | grep :443Stop conflicting services before running deployment.
Check the service logs:
sudo journalctl -u flask -n 50
sudo journalctl -u redis6 -n 50Verify your subdomain registration:
nslookup [username][label].moraviancs.clickIf it doesn't resolve, re-run ./register_ip.sh
URL-Shortener/
├── app/
│ ├── requirements.txt
│ └── [application files]
├── flask.service
├── ec2_deploy.sh
├── register_ip.sh
├── up.sh
└── .env (created during deployment)
- Never commit
.envfiles to version control - Keep your bearer token secure
- SSL certificates are automatically renewed by certbot
- Redis runs locally and is not exposed externally
After deployment, certificates are stored at:
Certificate: /etc/letsencrypt/live/[subdomain].moraviancs.click/fullchain.pem
Private Key: /etc/letsencrypt/live/[subdomain].moraviancs.click/privkey.pem
For issues or questions, refer to the course documentation or contact your instructor.
For local development and testing:
The application persists link data in Redis instead of JSON files.
-
Install Redis:
- macOS:
brew install redis - Other platforms: See https://redis.io/docs/getting-started/installation/
- macOS:
-
Start a local Redis server with default configuration:
redis-server
The app assumes
redis://localhost:6379/0whenREDIS_URLis not set. -
(Optional) Point the app to a different Redis instance:
export REDIS_URL=redis://<host>:<port>/<db>
With Redis running:
cd app
pip install -r requirements.txt
flask runAll short code mappings will be stored under the link: namespace in Redis.