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:
-
Prepare your code & GitHub repo
-
Write your Dockerfile
-
Create & configure fly.toml
-
Set up Fly.io secrets
-
Connect your GitHub repo to Fly.io (optional CI)
-
Deploy & monitor
-
Test your live app
1. Prepare Your Code & GitHub Repo
-
Project Layout
concept_explorer/
├── backend/
│ ├── main.py
│ ├── explorer.py
│ ├── models.py
│ └── requirements.txt
├── frontend/
│ └── index.html
├── Dockerfile
├── fly.toml
└── .gitignore
-
-
Create .gitignore at the repo root:
# Python & env
__pycache__/
*.py[cod]
.env
venv/
backend/*.pyc
# Docker
.dockerignore
# IDE
.idea/
.vscode/
-
-
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:
-
Via CLI
flyctl secrets set GEMINI_API_KEY=your‑gemini‑key OPENAI_API_KEY=your‑openai‑key -a concept-explorer
-
-
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)
-
In the Fly Dashboard, go to Deployments → Connect repository.
-
Authorize your GitHub org & pick the concept_explorer repo + main branch.
-
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
-
Frontend
Visit:
https://concept-explorer.fly.dev/
-
-
Stream Endpoint
Test SSE:
curl "https://concept-explorer.fly.dev/stream_exploration?root_concept=vedanta&provider=gemini&depth=2"
-
-
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
-
Log in to Namecheap and go to Domain List → Manage next to your domain.
-
Click the Advanced DNS tab.
-
Under Host Records, add two records:
Type |
Host |
Value |
TTL |
---|---|---|---|
A |
@ |
<YOUR_IPV4_ADDRESS> |
Automatic |
AAAA |
@ |
<YOUR_IPV6_ADDRESS> |
Automatic |
-
-
(Optional) To support www, add a CNAME:
Type |
Host |
Value |
TTL |
---|---|---|---|
CNAME |
www |
<YOUR_FLY_APP_NAME>.fly.dev |
Automatic |
-
-
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