We use cookies to enhance your experience on the site
CodeWorlds

Deployment - publishing on the internet

Congratulations, @name! Darwin here with the last lesson of Module 5 - deploying a Flask application! πŸš€πŸŒ

You've built a functioning Safari Database application with forms, authentication and templates. Now it's time to publish it on the internet so the world can use it! 🌍

Safari Analogy: Deployment is like opening the park to the public - until now the park only operated internally (localhost), now you're opening the gates for tourists from all over the world (internet)! 🦁🌐

Development vs Production

Development (localhost)

βœ… `app.run(debug=True)` - development server βœ… Auto-reload after code changes βœ… Detailed errors in the browser βœ… Localhost only - not accessible from the internet βœ… Slow - not optimized

Production (internet)

βœ… WSGI server (Gunicorn, uWSGI) βœ… No `debug=True` - security! βœ… Environment variables - SECRET_KEY, DATABASE_URL βœ… Publicly accessible - anyone can visit βœ… Fast - optimized

⚠️ NEVER use `app.run(debug=True)` in production!

WSGI Server - Gunicorn

Gunicorn (Green Unicorn) is a popular WSGI server for Flask/Django applications.

WSGI = Web Server Gateway Interface - a standard for communication between a server and a Python application.

Installation

1pip install gunicorn

Running

1# Basic
2gunicorn app:app
3
4# With port and workers specified
5gunicorn app:app --bind 0.0.0.0:8000 --workers 4
6
7# With reload (dev only)
8gunicorn app:app --reload

Format: `gunicorn <module>:<app_variable>`

  • `app` - file name (app.py)
  • `app` - Flask variable name (app = Flask(name))

Preparing for deployment

1. requirements.txt file

Save all dependencies:

1pip freeze > requirements.txt

requirements.txt:

1Flask==3.0.0
2Flask-WTF==1.2.1
3Flask-Login==0.6.3
4Werkzeug==3.0.1
5gunicorn==21.2.0

2. Environment variables

NEVER commit SECRET_KEY and sensitive data to git!

Use environment variables:

1# app.py
2import os
3
4app = Flask(__name__)
5
6# Get from environment variables
7app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') or 'dev-fallback-key'
8app.config['DATABASE_URL'] = os.environ.get('DATABASE_URL') or 'sqlite:///dev.db'
9
10# Debug only in dev
11app.config['DEBUG'] = os.environ.get('FLASK_ENV') == 'development'

3. .gitignore

1# .gitignore
2venv/
3__pycache__/
4*.pyc
5*.pyo
6.env
7instance/
8.DS_Store

4. Procfile (for platforms like Render/Heroku)

1web: gunicorn app:app

Procfile tells the platform how to run your application.

5. runtime.txt (optional)

1python-3.11.0

Specifies the Python version.

Deployment on Render (FREE!)

Render is a modern hosting platform with a free plan. A great alternative to Heroku!

Step 1: Prepare the application

Project structure:

1safari_web/
2β”œβ”€β”€ app.py
3β”œβ”€β”€ models.py
4β”œβ”€β”€ forms.py
5β”œβ”€β”€ requirements.txt
6β”œβ”€β”€ Procfile
7β”œβ”€β”€ .gitignore
8β”œβ”€β”€ templates/
9β”‚   └── ...
10└── static/
11    └── ...

app.py - last lines:

1if __name__ == '__main__':
2    # Only for local development
3    app.run(debug=True)

Render will run via Procfile, so `if name` won't execute!

Step 2: Push to GitHub

1git init
2git add .
3git commit -m "Initial commit - Safari Database"
4git branch -M main
5git remote add origin https://github.com/your-username/safari-web.git
6git push -u origin main

Step 3: Create Web Service on Render

  1. Go to https://render.com and register (FREE)

  2. Click "New +" β†’ "Web Service"

  3. Connect your GitHub repository

  4. Select the `safari-web` repository

  5. Configuration:

    • Name: safari-database
    • Environment: Python 3
    • Build Command: `pip install -r requirements.txt`
    • Start Command: `gunicorn app:app`
    • Plan: Free
  6. Environment Variables - add:

    • `SECRET_KEY` = `your-random-secret-key-here`
    • `FLASK_ENV` = `production`
  7. Click "Create Web Service"

Step 4: Deploy!

Render automatically:

  • Installs dependencies (`pip install -r requirements.txt`)
  • Runs Gunicorn (`gunicorn app:app`)
  • Assigns a domain (`https://safari-database.onrender.com`)

Congratulations! Your application is LIVE! πŸŽ‰πŸš€

Deployment on Railway (also FREE!)

Railway is another great platform with a simple setup.

Steps:

  1. https://railway.app - register
  2. "New Project" β†’ "Deploy from GitHub repo"
  3. Select the repository
  4. Railway automatically detects Flask!
  5. Add Environment Variables:
    • `SECRET_KEY`
    • `FLASK_ENV=production`
  6. Railway automatically deploys! βœ…

Domain: `https://safari-database.up.railway.app`

Deployment checklist

Before deployment make sure:

Security

  • [ ] `DEBUG = False` in production
  • [ ] SECRET_KEY as environment variable
  • [ ] Passwords hashed (werkzeug.security)
  • [ ] CSRF protection enabled (Flask-WTF)
  • [ ] .gitignore contains `venv/`, `.env`

Files

  • [ ] requirements.txt is up to date
  • [ ] Procfile created
  • [ ] .gitignore created
  • [ ] Static files properly configured

Database

  • [ ] In dev: SQLite
  • [ ] In prod: PostgreSQL (Render/Railway FREE tier!)
  • [ ] DATABASE_URL as environment variable

Testing

  • [ ] Application works locally
  • [ ] All routes work
  • [ ] Forms work
  • [ ] Login/registration works

Database in production

SQLite (Development)

1app.config['DATABASE_URL'] = 'sqlite:///safari.db'

Problems: SQLite is not recommended for production (concurrency issues).

PostgreSQL (Production)

Render/Railway offer FREE PostgreSQL!

Render: Add PostgreSQL Database β†’ copy DATABASE_URL

1import os
2
3database_url = os.environ.get('DATABASE_URL')
4
5if database_url and database_url.startswith('postgres://'):
6    # Render uses postgres://, but SQLAlchemy needs postgresql://
7    database_url = database_url.replace('postgres://', 'postgresql://', 1)
8
9app.config['SQLALCHEMY_DATABASE_URI'] = database_url or 'sqlite:///dev.db'

Static files in production

Flask automatically serves files from `static/`, but in production it's better to use a CDN or Nginx.

Basic Flask configuration:

1# app.py
2app = Flask(__name__)
3
4# Flask automatically serves static files from /static/
5# http://yourapp.com/static/css/style.css

In templates:

1<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
2<script src="{{ url_for('static', filename='js/script.js') }}"></script>

Monitoring and logs

Render Logs

Dashboard β†’ Your Web Service β†’ Logs

Railway Logs

Project β†’ Your Service β†’ Logs

Example logs:

1[2024-01-15 10:23:45] INFO: Starting gunicorn 21.2.0
2[2024-01-15 10:23:45] INFO: Listening at: http://0.0.0.0:10000
3[2024-01-15 10:23:45] INFO: Using worker: sync
4[2024-01-15 10:23:45] INFO: Booting worker with pid: 42

Updating the application

Render/Railway

  1. Make code changes locally
  2. Commit to git:
    1git add .
    2git commit -m "Update: Add new feature"
    3git push origin main
  3. Render/Railway automatically deploys the new version!

Auto-deploy = push to GitHub β†’ automatic deploy! πŸš€

Custom domain (optional)

Instead of `safari-database.onrender.com` you can use your own domain:

  1. Buy a domain (e.g. `safaridatabase.com`)
  2. Render/Railway β†’ Settings β†’ Custom Domain
  3. Add a CNAME record at your domain registrar
  4. Done! `https://safaridatabase.com` β†’ Your application

Alternative platforms

1. Fly.io

  • FREE tier
  • Global deployment
  • Great documentation

2. PythonAnywhere

  • FREE tier for Flask
  • Simple setup
  • Good for beginners

3. DigitalOcean App Platform

  • $5/month
  • More control
  • Scalable

4. AWS/Google Cloud/Azure

  • Advanced
  • More expensive
  • Full control

Example production-ready app.py

1# app.py
2import os
3from flask import Flask, render_template, redirect, url_for, flash
4from flask_login import LoginManager, login_user, logout_user, login_required, current_user
5from flask_sqlalchemy import SQLAlchemy
6
7app = Flask(__name__)
8
9# Configuration from environment variables
10app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') or 'dev-key-change-in-production'
11app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or 'sqlite:///dev.db'
12app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
13
14# Fix for Render PostgreSQL URL
15if app.config['SQLALCHEMY_DATABASE_URI'].startswith('postgres://'):
16    app.config['SQLALCHEMY_DATABASE_URI'] = app.config['SQLALCHEMY_DATABASE_URI'].replace('postgres://', 'postgresql://', 1)
17
18db = SQLAlchemy(app)
19login_manager = LoginManager(app)
20login_manager.login_view = 'login'
21
22# Models, routes, etc...
23
24if __name__ == '__main__':
25    # Only for local development
26    port = int(os.environ.get('PORT', 5000))
27    app.run(host='0.0.0.0', port=port, debug=os.environ.get('FLASK_ENV') == 'development')

Summary

In this lesson you learned:

  • βœ… Difference between development and production
  • βœ… WSGI servers (Gunicorn)
  • βœ… Preparing applications for deployment
  • βœ… Environment variables (SECRET_KEY, DATABASE_URL)
  • βœ… Deployment on Render (FREE!)
  • βœ… Deployment on Railway (FREE!)
  • βœ… Deployment checklist
  • βœ… Databases in production (PostgreSQL)
  • βœ… Static files in production
  • βœ… Monitoring and logs
  • βœ… Updating applications (auto-deploy)

Final Safari Analogy: Deployment is like the grand opening of a safari park - you prepared the infrastructure (code), hired staff (WSGI server), secured the park (SECRET_KEY, HTTPS), and opened the gates for tourists from all over the world (internet)! Your Flask application lives and runs 24/7 in the cloud! πŸ¦πŸŒπŸš€

Congratulations on Module 5!

You've built a complete web application with:

  • 🎨 Frontend (HTML, CSS, JavaScript)
  • 🐍 Backend (Flask)
  • πŸ›€οΈ Routing and view functions
  • πŸ“„ Jinja2 templates
  • πŸ“ Forms with validation (Flask-WTF)
  • πŸ” Authentication (Flask-Login)
  • πŸš€ Deployment on the internet (Render/Railway)

Safari Database is now LIVE and accessible to everyone on the internet! πŸŽ‰

Darwin is proud of you! Get ready for the next modules, where you'll learn advanced Python and AI techniques! πŸ€–πŸ

Go to CodeWorlds→