This commit is contained in:
2026-01-23 22:23:31 +01:00
parent f01de7a8e6
commit 3684d98456
5 changed files with 200 additions and 0 deletions

22
.dockerignore Normal file
View 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
View 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"]

View File

@@ -33,6 +33,100 @@ flask run --debug
Open http://127.0.0.1:5000 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'
```
Thats 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 ## Notes
- SQLite DB is stored at `instance/signage.sqlite`. - 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
View 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
View 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