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 (referencing server.py)
  • callable: app (the Flask instance returned by create_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:

  1. Clone the repository and enter the directory:

    git clone https://github.com/Allen7D/mini-shop-server.git
    cd mini-shop-server
  2. Install the uv package manager if not present:

    curl -LsSf https://astral.sh/uv/install.sh | sh
  3. Synchronize dependencies including Gunicorn:

    uv sync
  4. 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
    
  5. 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
  6. Configure Nginx to proxy to the Unix socket and serve static files from app/static/.

Summary

  • The application factory pattern in app/__init__.py centralizes Flask app creation, while server.py exposes the WSGI entry point as app.
  • Environment-based configuration loads app/config/secure.py when ENV_MODE is set to production values, ensuring DEBUG=False and secure credentials.
  • Gunicorn is pinned in pyproject.toml and invoked via uv 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →