Caddy & Python Flask

Download Caddy

curl -L "https://caddyserver.com/api/download?os=linux&arch=amd64" -o /tmp/caddy
sudo chown root:root /tmp/caddy
sudo chmod +x /tmp/caddy
sudo mv /tmp/caddy /usr/local/bin/caddy

Or if you want to use systemd service in production on Debian https://caddyserver.com/docs/install#debian-ubuntu-raspbian

Run Caddy

sudo caddy reverse-proxy --from example.com --to 127.0.0.1:5000

The ACME Success Checklist

Caddy's auto-HTTPS is fully automatic, but the ACME Let's Encrypt challenge will strictly fail if the following environmental conditions are not met before you hit Enter:

  1. DNS A Record: example.com must be publicly registered and its DNS A record must point to the public IP address of the server running Caddy.
  2. Open Ports: Ports 80 and 443 must be open on your server's firewall and accessible from the public internet.
  3. Root Privileges: You generally must run Caddy with sudo (or as root) because non-root users are restricted from binding to privileged system ports (anything under port 1024, which includes 80 and 443).

When you run the command, Caddy will automatically generate a private key, solve the HTTP-01 challenge on port 80, download the certificate, and start serving your Flask app securely on port 443.

More on Let's Encrypt https://letsencrypt.org/getting-started/

sudo apt update
sudo apt install python3-venv python3-pip -y
mkdir app
cd app
python3 -m venv .venv
source .venv/bin/activate
pip install Flask Authlib requests certifi cryptography

nano app.py

import os
from flask import Flask, url_for, session, redirect
from authlib.integrations.flask_client import OAuth

app = Flask(__name__)
app.secret_key = os.urandom(24)
app.config.update(
    GOOGLE_CLIENT_ID='YOUR_GOOGLE_CLIENT_ID',
    GOOGLE_CLIENT_SECRET='YOUR_GOOGLE_CLIENT_SECRET'
)

oauth = OAuth(app)
google = oauth.register(
    name='google',
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid email profile'}
)

@app.route('/')
def index():
    user = session.get('user')
    if user:
        return f"Hello, {user.get('email')}. <br><a href='/logout'>Logout</a>"
    return '<a href="/login">Login with Google</a>'

@app.route('/login')
def login():
    redirect_uri = url_for('auth', _external=True)
    return google.authorize_redirect(redirect_uri)

@app.route('/auth')
def auth():
    token = google.authorize_access_token()
    user = token.get('userinfo')
    session['user'] = user
    return redirect('/')

@app.route('/logout')
def logout():
    session.pop('user', None)
    return redirect('/')

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
python3 app.py

Now if your DNS is setup to point the the correct ip address, and if TCP 443 is exposed this should work.

For containerized deployments you can use:

https://docs.docker.com/compose/

https://docs.docker.com/reference/samples/flask/

https://github.com/caddyserver/ingress

and deploy your app via a deploy in Kubernetes using a helm chart. See https://helm.sh/docs/chart_template_guide/getting_started/.

This is a simple example of how applications work. Sadly, many software developers or Cloud Engineers can't do this as they have very little understanding of how the Internet & interconnected systems work beyond cloud UI button clicking. As you can see it's not that difficult. Our example of minimalistic code makes it easy to see how simple.

Curious about the OSI Model check out:

https://www.cloudflare.com/learning/ddos/glossary/open-systems-interconnection-model-osi/

https://en.wikipedia.org/wiki/OSI_model


More Notes

Why use package manager?

The absolute safest way to install software like Caddy is through your operating system's official package manager (like apt, dnf, or pacman) using Caddy's official repository.

Using a package manager is superior because:

  1. Cryptographic Verification: It automatically checks GPG signatures to guarantee the binary hasn't been tampered with.
  2. Automated Updates: You receive security patches through your normal system update routine rather than having to manually curl the binary again.
  3. System Integration: It automatically configures the necessary systemd services, dedicated users, and proper folder permissions (like /etc/caddy and /var/lib/caddy).