Deploying to Fly.io¶
Fly.io is a modern platform for running containerised apps globally. It provisions hardware, handles TLS/HTTPS, and auto-scales your instances.
This project ships with a multi-stage Dockerfile that builds the MkDocs documentation site and embeds it directly into the container. After deployment, the documentation is served at the root URL and the API is available under /api.
URL Map (Post-Deployment)¶
| Path | What is served |
|---|---|
/ |
MkDocs documentation home page |
/getting-started/ |
Documentation sub-pages |
/api/docs |
Swagger / OpenAPI interactive UI |
/api/redoc |
ReDoc alternative API reference |
/api/openapi.json |
Raw OpenAPI schema |
/api/v1/chat/ask |
Primary RAG endpoint |
/api/v1/training/data |
Training management |
/health |
Liveness probe (used by Fly.io) |
Prerequisites¶
- A Fly.io account (free tier available)
- The Fly CLI (
flyctl) installed
1. Install the Fly CLI¶
Verify:
2. Authenticate¶
3. Review fly.toml¶
The project ships with a production-ready fly.toml:
app = "dbn-analytics-poc"
primary_region = "iad" # US East
[build]
dockerfile = "Dockerfile"
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
[[http_service.checks]]
path = "/health"
interval = "30s"
timeout = "5s"
[env]
APP_NAME = "DBN Analytics POC API"
VANNA_MODEL = "gpt-4o"
[[vm]]
cpu_kind = "shared"
cpus = 1
memory_mb = 1024
Change region
Run fly platform regions to see all options. Replace iad with lhr (London) or fra (Frankfurt) for lower latency from Nigeria/Africa.
4. Provision the App (No Deploy Yet)¶
If the app name dbn-analytics-poc is already taken, Fly will prompt for a new name. Update the app field in fly.toml to match.
5. Set Secrets¶
Since .env is excluded by .dockerignore, inject secrets directly:
Verify:
6. Deploy¶
The deploy process:
- Sends the build context to Fly's remote builder
- Runs the docs-builder stage —
mkdocs buildgenerates thesite/folder - Runs the production stage — copies
site/into the final image alongside the FastAPI app - Starts the container with
uvicorn main:app --host 0.0.0.0 --port 8080
7. Visit Your App¶
This opens https://dbn-analytics-poc.fly.dev in your browser — which displays the MkDocs documentation home page served by FastAPI.
| URL | Content |
|---|---|
https://dbn-analytics-poc.fly.dev/ |
📖 Documentation home |
https://dbn-analytics-poc.fly.dev/api/docs |
⚡ Swagger UI |
https://dbn-analytics-poc.fly.dev/health |
✅ Health probe |
8. Re-Deploy After Changes¶
After any code or documentation change, simply run:
The multi-stage build automatically rebuilds the docs and redeploys.
Useful Commands¶
| Command | Description |
|---|---|
fly status |
View machine and release status |
fly logs |
Stream live application logs |
fly ssh console |
SSH into the running container |
fly secrets set KEY=VALUE |
Add or update a secret |
fly secrets list |
List all secret names (not values) |
fly scale memory 2048 |
Increase RAM if needed |
fly open |
Open the live app in your browser |
How the Static File Serving Works¶
The Dockerfile uses a multi-stage build:
# Stage 1: Build MkDocs site
FROM python:3.10-slim AS docs-builder
RUN pip install mkdocs-material
COPY mkdocs.yml .
COPY docs/ ./docs/
RUN mkdocs build --site-dir site # → generates site/
# Stage 2: Production image
FROM python:3.10-slim AS production
COPY --from=docs-builder /app/site ./site # embed docs
COPY . .
RUN pip install -r requirements.txt
CMD ["uvicorn", "main:app", ...]
main.py detects the site/ directory at startup and mounts it:
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
if os.path.isdir("site"):
# Serve docs home at /
@app.get("/", include_in_schema=False)
def serve_docs_home():
return FileResponse("site/index.html")
# Catch-all: serve any MkDocs-generated sub-page
@app.get("/{full_path:path}", include_in_schema=False)
def serve_docs_page(full_path: str):
... # resolves to site/<path>/index.html or falls back to site/index.html