Wednesday, April 16, 2025

 

Deploying Your FastAPI + Simple Frontend App on Fly.io


This guide walks you through every step—from local setup to a live endpoint on Fly.io—using the “Concept Explorer” example. You’ll learn how to:

  1. Prepare your code & GitHub repo

  2. Write your Dockerfile

  3. Create & configure fly.toml

  4. Set up Fly.io secrets

  5. Connect your GitHub repo to Fly.io (optional CI)

  6. Deploy & monitor

  7. Test your live app


1. Prepare Your Code & GitHub Repo

  1. Project Layout

concept_explorer/
├── backend/
│   ├── main.py
│   ├── explorer.py
│   ├── models.py
│   └── requirements.txt
├── frontend/
│   └── index.html
├── Dockerfile
├── fly.toml
└── .gitignore


  1. Create .gitignore at the repo root:

# Python & env
__pycache__/
*.py[cod]
.env
venv/
backend/*.pyc

# Docker
.dockerignore

# IDE
.idea/
.vscode/


  1. Initialize Git & push to GitHub

cd concept_explorer
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/your‑username/concept_explorer.git
git push -u origin main



2. Write Your 

Dockerfile


Place this at the project root as Dockerfile:

# syntax=docker/dockerfile:1

############################
# 1. Build stage
############################
FROM python:3.11-slim AS builder
WORKDIR /app
RUN apt-get update \
 && apt-get install -y --no-install-recommends build-essential \
 && rm -rf /var/lib/apt/lists/*
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

############################
# 2. Final image
############################
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin

# Copy application code
COPY backend/ ./backend
COPY frontend/ ./frontend

EXPOSE 8000
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"]
Tip: You can test locally with:
docker build -t concept-explorer .
docker run -p 8000:8000 concept-explorer
# then visit http://localhost:8000



3. Create & Configure 

fly.toml


A) Generate via CLI


If you have flyctl installed:

flyctl launch --name concept-explorer --region den --dockerfile Dockerfile --no-deploy

That creates fly.toml.


B) Manual 

fly.toml


Otherwise, create fly.toml at root:

app = "concept-explorer"
primary_region = "den"

[build]
  dockerfile = "Dockerfile"

[env]
  # non-sensitive defaults, if any
  LOG_LEVEL = "info"

[http_service]
  internal_port = 8000
  force_https = true
  auto_start_machines = true
  auto_stop_machines = true

  • app must match your Fly app’s name.

  • internal_port = the port your Uvicorn server listens on (8000).


4. Set Up Fly.io Secrets


Your .env holds keys locally, but in production you must inject them as Fly Secrets:

  1. Via CLI

flyctl secrets set GEMINI_API_KEY=your‑gemini‑key OPENAI_API_KEY=your‑openai‑key -a concept-explorer


  1. Via Dashboard

    • Visit your app → Secrets → New Secret.

    • Add GEMINI_API_KEY and/or OPENAI_API_KEY.


Secrets become environment variables at runtime, so your backend/main.py—which calls load_dotenv()—will pick them up via os.getenv(...).


5. Connect GitHub → Fly.io (optional CI)

  1. In the Fly Dashboard, go to Deployments → Connect repository.

  2. Authorize your GitHub org & pick the concept_explorer repo + main branch.

  3. Enable “Auto Deploy on push”.


Now every git push to main triggers Fly’s build+deploy pipeline automatically.


6. Deploy & Monitor


A) First Deploy (or manual)


If you didn’t enable auto-CI, run:

flyctl deploy -a concept-explorer

Fly will:

  • Build your Docker image using Dockerfile.

  • Push it to Fly’s registry.

  • Launch (or restart) a VM running your container.

  • Wire up your HTTP service on port 80/443 → container’s port 8000.


B) Watch Live Logs

flyctl logs -a concept-explorer --tail

Or in the Dashboard under Live Logs. Look for:

  • Serving static files from: ...frontend

  • Uvicorn running on 0.0.0.0:8000

  • No ModuleNotFoundError or missing‐key errors.


7. Test Your Live App

  1. Frontend

    Visit:

https://concept-explorer.fly.dev/


  1. Stream Endpoint

    Test SSE:

curl "https://concept-explorer.fly.dev/stream_exploration?root_concept=vedanta&provider=gemini&depth=2"


  1. Health Check

curl https://concept-explorer.fly.dev/health
# should return {"status":"ok"}



Troubleshooting

  • ModuleNotFoundError:

    Make sure your imports use relative paths (e.g. from .explorer import ConceptExplorer) and that backend/ is copied in your Dockerfile.

  • Secrets not applied:

    • Verify fly secrets list -a concept-explorer.

    • Redeploy to inject new secrets: flyctl deploy -a concept-explorer.

  • No build on push:

    • Confirm GitHub integration under Deployments → “Connected to GitHub”.

    • Ensure .github/workflows/fly.yml exists if you use Actions, or rely on Fly’s GitHub App.

  • Port binding errors:

    • Your app must listen on 0.0.0.0:8000 (not 127.0.0.1).

    • fly.toml → [http_service] internal_port = 8000.



Part 2: Custom Domain on Fly.io

 

 


1. Deploy your app on Fly.io


Make sure your app is running on Fly.io and that you’ve confirmed its public IPv4 and IPv6 addresses:

flyctl ips list --app <YOUR_APP_NAME>

You’ll see something like:

VERSION   IP                  TYPE
v4        <YOUR_IPV4_ADDRESS>   public (shared)
v6        <YOUR_IPV6_ADDRESS>   public (dedicated)



2. Add DNS records in Namecheap

  1. Log in to Namecheap and go to Domain List → Manage next to your domain.

  2. Click the Advanced DNS tab.

  3. Under Host Records, add two records:

Type

Host

Value

TTL

A

@

<YOUR_IPV4_ADDRESS>

Automatic

AAAA

@

<YOUR_IPV6_ADDRESS>

Automatic


  1. (Optional) To support www, add a CNAME:

Type

Host

Value

TTL

CNAME

www

<YOUR_FLY_APP_NAME>.fly.dev

Automatic


  1. Save your changes.


3. Request a TLS certificate on Fly.io


Fly.io will use Let’s Encrypt to issue a certificate once it can see your DNS changes.

flyctl certs create <YOUR_DOMAIN> --app <YOUR_APP_NAME>

You should see instructions if Fly still needs you to add an AAAA or A record—but since you’ve already pointed both, it will proceed automatically.


4. Verify issuance


Every few minutes, check the certificate status:

flyctl certs list --app <YOUR_APP_NAME>

You’ll see something like:

Host Name        Added           Status
<YOUR_DOMAIN>    2 minutes ago   OK (expires 2025‑XX‑XX)

When Status shows OK, your TLS cert is live.


5. Test your custom domain


Open in your browser or via curl:

curl -I https://<YOUR_DOMAIN>

You should get back a 200 OK (or the headers from your app) and a valid Let’s Encrypt certificate chain.


Tips & Troubleshooting

  • DNS propagation can take 5–15 minutes.

  • Ensure there are no conflicting records (e.g., an extra CNAME on @).

  • If, after 20 minutes, the certificate is still Awaiting configuration, you can remove & re‑create it:

flyctl certs remove <YOUR_DOMAIN> --app <YOUR_APP_NAME>
flyctl certs create <YOUR_DOMAIN> --app <YOUR_APP_NAME>


  • For a www‑only site, you can point www→Fly.io via CNAME and then redirect the root (@) to www using Namecheap’s URL Redirect feature.


That’s it! Your Namecheap domain will now serve your Fly.io app over HTTPS.



No comments:

Post a Comment