Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Ignore build artifacts and env
__pycache__/
*.py[cod]
.env
.env.*
redis_data/
*.log

# Docker
docker-compose.override.yml

# Editor
.vscode/
.idea/
7 changes: 6 additions & 1 deletion app/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from fastapi import FastAPI, Request, HTTPException
from fastapi import FastAPI, Request, Form, HTTPException
import asyncio
import os
from app.classifier import classify_urgency
from app.convo_store import ConvoStore
Expand All @@ -9,6 +10,10 @@
app = FastAPI()
store = ConvoStore(redis_url=settings.REDIS_URL)

@app.get("/health")
async def health():
return {"status": "ok"}

@app.post("/webhook")
async def webhook(request: Request):
# Twilio posts form-encoded data for incoming messages
Expand Down
27 changes: 27 additions & 0 deletions docker-compose.nginx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: '3.8'

services:
nginx:
image: nginx:1.25-alpine
depends_on:
- app
ports:
- "80:80"
- "443:443"
volumes:
- ./infra/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./infra/nginx/conf.d:/etc/nginx/conf.d:ro
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/www/certbot
restart: unless-stopped

certbot:
image: certbot/certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/www/certbot
entrypoint: /bin/sh -c 'trap exit TERM; while :; do sleep 12h & wait $${!}; certbot renew; done'

volumes:
certbot-etc:
certbot-var:
59 changes: 59 additions & 0 deletions infra/nginx/conf.d/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
upstream app {
# Use the docker-compose service name or Kubernetes service name
server app:8000;
}

server {
listen 80;
server_name _;

# Allow ACME challenges (certbot) to use /.well-known/acme-challenge/
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

# Health endpoint (transparent proxy to app health)
location = /health {
proxy_pass http://app/health;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}

# Main app (webhook + API)
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# Forward original request headers (Twilio/Meta signature headers are needed)
proxy_set_header X-Original-URI $request_uri;
proxy_http_version 1.1;
proxy_set_header Connection "";

# Disable buffering for proxied responses (good for streaming or low-latency)
proxy_buffering off;

# Timeouts (tune as needed)
proxy_read_timeout 120s;
proxy_send_timeout 120s;

# Max body size (increase if you accept large media)
client_max_body_size 8M;

# Proxy buffers (tune for throughput)
proxy_buffers 8 16k;
proxy_buffer_size 32k;
}

# Security headers for TLS (set only when TLS is enabled)
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
26 changes: 26 additions & 0 deletions infra/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

sendfile on;
tcp_nopush on;
keepalive_timeout 65;
server_tokens off; # hide nginx version in responses

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;

gzip on;
gzip_types text/plain application/json application/javascript text/css application/xml;

include /etc/nginx/conf.d/*.conf;
}
Loading