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 → SettingsCustom 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