Production hardening + container for public hosting
- Request body cap (16KB), search query cap, input range validation (year 1800-2399, date/time fields, lat/lon bounds) - Dockerfile (gunicorn, 2 workers) + compose binding 127.0.0.1:7799 for cloudflared-fronted deployment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c5f848733a
commit
77a522a16f
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@ -0,0 +1,5 @@
|
||||
.venv/
|
||||
.git/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.DS_Store
|
||||
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt gunicorn==23.0.0
|
||||
COPY . .
|
||||
EXPOSE 7799
|
||||
# 2 workers is plenty: chart computation is a few ms; timezonefinder/geonames load per worker
|
||||
CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:7799", "--access-logfile", "-", "app:app"]
|
||||
9
app.py
9
app.py
@ -6,6 +6,7 @@ import geo
|
||||
import interp
|
||||
|
||||
app = Flask(__name__, static_folder="static", static_url_path="")
|
||||
app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 # chart inputs are tiny; cap request bodies
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@ -15,7 +16,7 @@ def index():
|
||||
|
||||
@app.get("/api/search")
|
||||
def api_search():
|
||||
q = request.args.get("q", "")
|
||||
q = request.args.get("q", "")[:64]
|
||||
return jsonify(geo.search_cities(q))
|
||||
|
||||
|
||||
@ -41,6 +42,12 @@ def cast(d):
|
||||
house_system = "P"
|
||||
except (KeyError, TypeError) as e:
|
||||
raise ValueError(f"bad input: {e}")
|
||||
if not (1800 <= year <= 2399):
|
||||
raise ValueError("year must be 1800-2399 (ephemeris range)")
|
||||
if not (1 <= month <= 12 and 1 <= day <= 31 and 0 <= hour <= 23 and 0 <= minute <= 59):
|
||||
raise ValueError("date/time out of range")
|
||||
if not (-90 <= lat <= 90 and -180 <= lon <= 180):
|
||||
raise ValueError("coordinates out of range")
|
||||
|
||||
if d.get("utc_offset") not in (None, ""):
|
||||
offset, tzname = float(d["utc_offset"]), "manual"
|
||||
|
||||
7
compose.yml
Normal file
7
compose.yml
Normal file
@ -0,0 +1,7 @@
|
||||
services:
|
||||
nategodd:
|
||||
build: .
|
||||
container_name: nategodd
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:7799:7799" # cloudflared reaches it via localhost; never exposed directly
|
||||
Loading…
Reference in New Issue
Block a user