prodv1
This commit is contained in:
22
.dockerignore
Normal file
22
.dockerignore
Normal file
@@ -0,0 +1,22 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
.venv/
|
||||
venv/
|
||||
|
||||
instance/
|
||||
app/static/uploads/
|
||||
|
||||
.env
|
||||
.flaskenv
|
||||
|
||||
*.sqlite
|
||||
|
||||
scripts/
|
||||
|
||||
README.md
|
||||
30
Dockerfile
Normal file
30
Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# System deps (kept minimal). Pillow may need some libs; for most cases this is fine on slim.
|
||||
# If you hit Pillow build/runtime issues, consider adding: libjpeg62-turbo, zlib1g, etc.
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt \
|
||||
&& pip install --no-cache-dir gunicorn
|
||||
|
||||
COPY . .
|
||||
|
||||
# Create runtime dirs (also mountable as volumes)
|
||||
RUN mkdir -p instance app/static/uploads
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# Default config (override at runtime)
|
||||
ENV FLASK_ENV=production \
|
||||
GUNICORN_WORKERS=2 \
|
||||
GUNICORN_BIND=0.0.0.0:8000
|
||||
|
||||
# Run via WSGI entrypoint
|
||||
CMD ["sh", "-c", "gunicorn -w ${GUNICORN_WORKERS} -b ${GUNICORN_BIND} wsgi:app"]
|
||||
98
README.md
98
README.md
@@ -33,6 +33,100 @@ flask run --debug
|
||||
|
||||
Open http://127.0.0.1:5000
|
||||
|
||||
## Production (WSGI)
|
||||
|
||||
This repo includes a `wsgi.py` entrypoint for production WSGI servers.
|
||||
|
||||
### Important (Windows)
|
||||
|
||||
If you try to run Gunicorn directly on Windows you will see an error like:
|
||||
|
||||
```
|
||||
ModuleNotFoundError: No module named 'fcntl'
|
||||
```
|
||||
|
||||
That’s expected: **Gunicorn is Unix-only**. On Windows, run the app via:
|
||||
|
||||
- **Docker** (recommended) so Gunicorn runs inside a Linux container, or
|
||||
- **WSL2/Linux** (Gunicorn works), or
|
||||
- use a Windows-native WSGI server (e.g. Waitress) instead of Gunicorn.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# gunicorn (Linux)
|
||||
gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app
|
||||
|
||||
# uWSGI
|
||||
uwsgi --http :8000 --wsgi-file wsgi.py --callable app
|
||||
```
|
||||
|
||||
Note: unlike `flask run`, WSGI servers typically don't auto-load `.env` / `.flaskenv`.
|
||||
`wsgi.py` attempts to load `.env` (best-effort), but for real production you should set
|
||||
environment variables via your process manager / secrets.
|
||||
|
||||
## Docker
|
||||
|
||||
### Docker Compose (recommended)
|
||||
|
||||
This repo includes a `docker-compose.yml` for a one-command startup.
|
||||
|
||||
```powershell
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
Run in the background:
|
||||
|
||||
```powershell
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Stop:
|
||||
|
||||
```powershell
|
||||
docker compose down
|
||||
```
|
||||
|
||||
Data persistence:
|
||||
|
||||
- SQLite DB is mounted to `./instance` on your host
|
||||
- uploads are mounted to `./app/static/uploads` on your host
|
||||
|
||||
Build:
|
||||
|
||||
```bash
|
||||
docker build -t signage:latest .
|
||||
```
|
||||
|
||||
Run (with persistent SQLite DB + uploads):
|
||||
|
||||
```bash
|
||||
docker run --rm -p 8000:8000 \
|
||||
-e SECRET_KEY="change-me" \
|
||||
-v %cd%/instance:/app/instance \
|
||||
-v %cd%/app/static/uploads:/app/app/static/uploads \
|
||||
signage:latest
|
||||
```
|
||||
|
||||
PowerShell variant (sometimes volume path quoting is easier):
|
||||
|
||||
```powershell
|
||||
docker run --rm -p 8000:8000 `
|
||||
-e SECRET_KEY="change-me" `
|
||||
-v "${PWD}/instance:/app/instance" `
|
||||
-v "${PWD}/app/static/uploads:/app/app/static/uploads" `
|
||||
signage:latest
|
||||
```
|
||||
|
||||
Then open: http://127.0.0.1:8000
|
||||
|
||||
Notes:
|
||||
|
||||
- The container starts with Gunicorn using `wsgi:app`.
|
||||
- You can override Gunicorn settings via env vars:
|
||||
- `GUNICORN_WORKERS` (default: 2)
|
||||
- `GUNICORN_BIND` (default: `0.0.0.0:8000`)
|
||||
|
||||
## Notes
|
||||
|
||||
- SQLite DB is stored at `instance/signage.sqlite`.
|
||||
@@ -121,3 +215,7 @@ If the reset email is not received:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
16
docker-compose.yml
Normal file
16
docker-compose.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: signage:latest
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
# Override in a .env file or your shell; this default is only for convenience.
|
||||
SECRET_KEY: "change-me"
|
||||
# Optional overrides (the Dockerfile already defaults these)
|
||||
GUNICORN_WORKERS: "2"
|
||||
GUNICORN_BIND: "0.0.0.0:8000"
|
||||
volumes:
|
||||
# Persist SQLite DB and uploads on the host
|
||||
- ./instance:/app/instance
|
||||
- ./app/static/uploads:/app/app/static/uploads
|
||||
34
wsgi.py
Normal file
34
wsgi.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""WSGI entrypoint for production servers (gunicorn/uWSGI/etc.).
|
||||
|
||||
This file exposes a module-level WSGI callable named `app` (and `application`)
|
||||
so common servers can run the project without relying on Flask's dev server.
|
||||
|
||||
Examples:
|
||||
gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app
|
||||
uwsgi --http :8000 --wsgi-file wsgi.py --callable app
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
|
||||
# `flask run` loads .env/.flaskenv automatically via python-dotenv.
|
||||
# Production WSGI servers typically *don't*, so we best-effort load `.env` here.
|
||||
# In real production, prefer setting environment variables via your process manager.
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(os.environ.get("DOTENV_PATH", ".env"), override=False)
|
||||
except Exception:
|
||||
# If python-dotenv isn't installed (or any other issue occurs), continue.
|
||||
pass
|
||||
|
||||
|
||||
from app import create_app
|
||||
|
||||
|
||||
app = create_app()
|
||||
|
||||
# Some servers (and hosting platforms) look specifically for `application`.
|
||||
application = app
|
||||
Reference in New Issue
Block a user