In this tutorial, we'll develop a URL shortener with Flask Python framework.
A URL shortener is a web application that converts long URLs into shorter, more manageable links while allowing redirection to the original address. In this tutorial, we will develop a URL shortener using Flask, Python, and SQLAlchemy. The focus will be on production-grade code with scalability, performance, and security in mind.
Develop a URL Shortener with Flask
Step 1: Setting Up the Project
Start by setting up your Python environment. Create a directory for the project and initialize a virtual environment:
mkdir flask-url-shortener
cd flask-url-shortener
python3 -m venv venv
source venv/bin/activate
Install Flask, SQLAlchemy, and other required dependencies:
pip install flask flask-sqlalchemy flask-migrate validators gunicorn flask-limiter
Step 2: Structuring the Flask Application
Organize the application into a modular structure:
flask-url-shortener/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ ├── utils.py
│ └── config.py
├── migrations/
├── venv/
├── run.py
└── requirements.txt
Create a app
directory
mkdir app
Step 3: Writing the Configuration
Create a config.py
file to store configurations:
nano config.py
Add following code
import os
class Config:
SECRET_KEY = os.environ.get("SECRET_KEY", "your_secret_key")
SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL", "sqlite:///url_shortener.db")
SQLALCHEMY_TRACK_MODIFICATIONS = False
FLASK_ENV = 'production' # Set to production
Note: We have used SQLite for the demonstration purpose. You should use PostgresSQL or MongoDB.
Step 4: Initializing the Flask Application
In __init__.py
, initialize the Flask app, SQLAlchemy, and Flask-Migrate:
nano __init__.py
Add following code
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from .config import Config
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
migrate.init_app(app, db)
from .routes import main
app.register_blueprint(main)
return app
Step 5: Designing the Database Model
In models.py
, define the database schema for storing original and shortened URLs:
nano models.py
Add following code
from . import db
import string
import random
class URL(db.Model):
id = db.Column(db.Integer, primary_key=True)
original_url = db.Column(db.String(2048), nullable=False)
short_url = db.Column(db.String(6), unique=True, nullable=False)
def generate_short_url(self):
characters = string.ascii_letters + string.digits
return ''.join(random.choices(characters, k=6))
Step 6: Writing Helper Functions
In utils.py
, write utility functions for validation and generating short URLs:
nano utils.py
Add following code
import validators
def validate_url(url):
return validators.url(url)
Step 7: Developing Routes
In routes.py
, define routes for shortening URLs and handling redirections:
nano routes.py
Add following code
from flask import Blueprint, request, jsonify, redirect
from .models import URL, db
from .utils import validate_url
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from flask import current_app
main = Blueprint('main', __name__)
@main.route('/shorten', methods=['POST'])
def shorten_url():
data = request.get_json()
original_url = data.get("original_url")
if not validate_url(original_url):
return jsonify({"error": "Invalid URL"}), 400
existing_url = URL.query.filter_by(original_url=original_url).first()
if existing_url:
return jsonify({"short_url": existing_url.short_url}), 200
url = URL(original_url=original_url)
url.short_url = url.generate_short_url()
db.session.add(url)
db.session.commit()
return jsonify({"short_url": url.short_url}), 201
@main.route('/<short_url>', methods=['GET'])
def redirect_to_original(short_url):
url = URL.query.filter_by(short_url=short_url).first_or_404()
return redirect(url.original_url)
limiter = Limiter(
get_remote_address,
app=current_app,
default_limits=["200 per day", "50 per hour"]
)
Step 8: Running the Application
Create run.py
to run the application:
nano run.py
Add following code
from app import create_app
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
Run database migrations:
flask db init
flask db migrate -m "Initial migration"
flask db upgrade
Start the application:
gunicorn -w 4 -b 127.0.0.1:5000 run:app
-w 4
: Specifies 4 worker processes.-b 127.0.0.1:5000
: Binds the application to localhost on port5000
.
Step 9: Testing the Application
- Use a tool like curl or Postman to send a POST request to
/shorten
with a JSON payload containingoriginal_url
. - Access the generated short URL in a browser or via a GET request to test redirection.
Example cURL commands:
# Shorten URL
curl -X POST -H "Content-Type: application/json" \
-d '{"original_url": "https://example.com"}' \
http://127.0.0.1:5000/shorten
output:
{
"short_url": "FxFIRp"
}
Redirect using the short URL
curl -v http://127.0.0.1:5000/<short_url>
Step 10: Configure Nginx
Install Nginx:
sudo apt update
sudo apt install nginx
Create an Nginx configuration file for your Flask app. For example:
sudo nano /etc/nginx/sites-available/url_shortener
Add the following content:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Note: Replace your-domain.com
with your domain name.
Enable the site by creating a symlink:
sudo ln -s /etc/nginx/sites-available/url_shortener /etc/nginx/sites-enabled/
Test the Nginx configuration and reload:
sudo nginx -t
sudo systemctl reload nginx
Step 11: Configure Systemd for Gunicorn
Create a Gunicorn systemd service file:
sudo nano /etc/systemd/system/url_shortener.service
Add the following content:
[Unit]
Description=Gunicorn instance to serve Flask URL Shortener
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/flask-url-shortener
Environment="PATH=/path/to/flask-url-shortener/venv/bin"
ExecStart=/path/to/flask-url-shortener/venv/bin/gunicorn -w 4 -b 127.0.0.1:5000 run:app
[Install]
WantedBy=multi-user.target
Replace /path/to/flask-url-shortener with the absolute path to your project.
Note: Replace /path/to/flask-url-shortener with your path
Start and enable the service:
sudo systemctl start url_shortener
sudo systemctl enable url_shortener
Check the status:
sudo systemctl status url_shortener
Step 12: Secure with HTTPS
Install Certbot for Nginx:
sudo apt install certbot python3-certbot-nginx
Obtain and configure a Let's Encrypt SSL certificate:
sudo certbot --nginx -d your-domain.com
Automatically renew certificates:
sudo systemctl enable certbot.timer
Step 13: Testing the Setup
Access your application using https://your-domain.com.
Test API endpoints with tools like Postman or curl to verify functionality.
Conclusion
We've developed a URL shortener with Flask Python framework. This tutorial covered the development of a production-grade URL shortener using Flask and Python. The application is modular, secure, This production-grade URL shortener is secured with Gunicorn and Nginx, and it’s designed for easy scalability.
With SQLite as the database, it is best suited for small to medium traffic but can be upgraded to a more robust DBMS when needed, and extensible for future features such as analytics or user authentication. With SQLite as the database, it is best suited for small to medium traffic but can be upgraded to a more robust DBMS when needed.
Checkout our dedicated servers India, Instant KVM VPS, and Web Hosting India