Deploying mini-shop-server with Gunicorn: Production Structure and Configuration
The mini-shop-server uses a Flask application factory pattern where server.py exposes a WSGI-compatible app object, loads production configuration from app/config/secure.py via the ENV_MODE environment variable, and runs under Gunicorn with process management through Supervisor and reverse-proxying via Nginx.
The mini-shop-server by allen7d is a Flask-based RESTful API designed for production scalability through clean separation of configuration and the WSGI server interface. Understanding its directory structure and deployment pipeline is essential for reliable production hosting behind reverse proxies.
Project Structure and Application Factory
The repository follows the application factory pattern, centralizing application initialization in app/__init__.py while exposing a standard WSGI entry point through server.py.
Entry Point and WSGI Interface
The server.py file serves as the minimal bootstrap script that Gunicorn imports as a module. It calls create_app() and exposes the resulting Flask instance as the app variable:
# app/__init__.py (lines 24-34)
def create_app():
app = Flask(__name__, static_folder="./static", template_folder="./templates")
load_config(app) # ← chooses secure or local config based on ENV_MODE
register_blueprint(app) # ← registers all API blueprints
register_plugin(app) # ← installs JSON encoder, CORS, DB, error handling, etc.
return app
When launching Gunicorn with the pattern server:app, the server imports server.py, triggering create_app() to instantiate the fully configured Flask application.
Environment-Based Configuration
The load_config() function dynamically selects configuration classes based on the ENV_MODE environment variable:
# app/__init__.py (lines 35-42)
def load_config(app):
if os.environ.get('ENV_MODE') == 'dev:local':
app.config.from_object('app.config.local_secure')
app.config.from_object('app.config.local_setting')
else:
app.config.from_object('app.config.secure')
app.config.from_object('app.config.setting')
For production deployments, set ENV_MODE to any value other than dev:local (such as prod) to force loading of production-grade settings from app/config/secure.py. This file contains critical production parameters including DEBUG = False, database connection URIs, and secret keys.
Gunicorn Configuration and Dependencies
The project pins Gunicorn as a core dependency and provides specific launch patterns optimized for both direct execution and process manager integration.
Dependency Declaration
Gunicorn is explicitly declared in the project manifest:
# pyproject.toml (line 29)
"gunicorn==21.2.0",
This ensures consistent WSGI server behavior across environments when using uv as the package manager.
WSGI Entry Point Specification
The standard Gunicorn invocation uses the server:app pattern, where:
- module:
server(referencingserver.py) - callable:
app(the Flask instance returned bycreate_app())
Worker and Binding Options
The repository README documents two primary binding strategies. For direct TCP binding during testing or containerized deployments:
# README.md (lines 36-45)
uv run gunicorn -w 4 -b 127.0.0.1:8080 server:app
For high-performance production deployments behind Nginx, use a Unix domain socket to avoid TCP overhead:
# Example from README (lines 55-61)
uv run gunicorn -w 4 -b unix:/home/workspace/mini-shop-server/server.sock server:app
The -w 4 flag initializes four worker processes. Adjust this value based on available CPU cores using $(nproc) for optimal request handling.
Production Process Management with Supervisor and Nginx
Running Gunicorn directly is insufficient for production reliability; the project integrates with Supervisor for process supervision and Nginx for static file serving and reverse proxying.
Supervisor Configuration
The README provides a complete Supervisor program definition that ensures automatic restarts and log management:
[program:server]
environment=PATH='/root/.local/share/virtualenvs/server-4o3oDD8t/bin/python'
command = /root/.local/share/virtualenvs/server-4o3oDD8t/bin/gunicorn -w 4 -b unix:/home/workspace/morning-star/server/server.sock server:app
directory = /home/workspace/morning-star/server
user = root
This configuration binds Gunicorn to a Unix socket at server.sock, monitors process health, and redirects logs to /tmp/blog_* files.
Nginx Reverse Proxy Setup
Nginx handles client connections and forwards dynamic requests to the Gunicorn socket while serving static assets directly:
# README.md (lines 28-34)
location / {
include proxy_params;
proxy_pass http://unix:/home/workspace/mini-shop-server/server.sock;
...
}
location /static/ {
alias /home/workspace/mini-shop-server/app/static/;
}
The proxy_pass directive targets the Unix socket path defined in the Supervisor command, creating a secure, high-throughput connection between the web server and the Flask application.
Step-by-Step Production Deployment
Follow this sequence to deploy the mini-shop-server on a production host:
-
Clone the repository and enter the directory:
git clone https://github.com/Allen7D/mini-shop-server.git cd mini-shop-server -
Install the
uvpackage manager if not present:curl -LsSf https://astral.sh/uv/install.sh | sh -
Synchronize dependencies including Gunicorn:
uv sync -
Configure the production environment:
export ENV_MODE=prod export FLASK_APP=server.py # Database credentials should be set via environment variables or hardcoded in secure.py -
Launch with Gunicorn via process manager or directly:
# Direct launch (development or Docker) uv run gunicorn -w 4 -b 0.0.0.0:8080 server:app # Production launch with Unix socket (use with Supervisor) uv run gunicorn -w 4 -b unix:/opt/mini-shop/server.sock server:app -
Configure Nginx to proxy to the Unix socket and serve static files from
app/static/.
Summary
- The application factory pattern in
app/__init__.pycentralizes Flask app creation, whileserver.pyexposes the WSGI entry point asapp. - Environment-based configuration loads
app/config/secure.pywhenENV_MODEis set to production values, ensuringDEBUG=Falseand secure credentials. - Gunicorn is pinned in
pyproject.tomland invoked viauv run gunicorn -w 4 server:app, supporting both TCP and Unix socket bindings. - Supervisor manages the Gunicorn process lifecycle, binding to Unix sockets for Nginx integration.
- Nginx serves as the reverse proxy and static file server, completing the production stack.
Frequently Asked Questions
How does mini-shop-server handle different configuration environments?
The load_config() function in app/__init__.py checks the ENV_MODE environment variable. When set to dev:local, it loads development settings; otherwise, it loads production configuration from app/config/secure.py and app/config/setting.py. This allows the same codebase to run in development and production modes without code changes.
What is the correct Gunicorn command for production deployment behind Nginx?
Use the Unix socket binding with multiple workers: uv run gunicorn -w 4 -b unix:/path/to/server.sock server:app. This command creates four worker processes and binds to a filesystem socket, which Nginx proxies via the proxy_pass http://unix:/path/to/server.sock; directive. Unix sockets provide better performance than TCP loops for local reverse proxying.
Where are the production secrets and database credentials stored?
Production secrets reside in app/config/secure.py, which is loaded when ENV_MODE is not set to dev:local. This file should contain DEBUG = False, SQLAlchemy database URIs, and secret keys. For containerized deployments, override these values using environment variables that Flask's configuration system reads at runtime.
Why is Supervisor recommended for running Gunicorn in production?
Supervisor ensures the Gunicorn process remains active through server reboots and application crashes. According to the repository's README, the Supervisor configuration specifies the Gunicorn command, working directory, user permissions, and log file locations. This eliminates the need for manual restarts and provides centralized logging for the WSGI server output.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →