- JavaScript 57.8%
- Python 37.9%
- Shell 2.2%
- Dockerfile 1.6%
- HTML 0.3%
- Other 0.2%
|
All checks were successful
Build and Push Docker Image / Build and Push (push) Successful in 2m13s
|
||
|---|---|---|
| .forgejo/workflows | ||
| actions | ||
| backend | ||
| frontend | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| generate-certs.sh | ||
| nginx.conf | ||
| README.md | ||
| start.sh | ||
Forwarding Manager
Office 365 email forwarding manager with multi-tenant OAuth support, round-robin and time-based routing. Built with a Python FastAPI backend and a React frontend, fully containerized with Docker.
Table of Contents
- Prerequisites
- Quick Start
- Architecture
- Environment Variables
- Volumes
- Ports
- Dockerfile Overview
- Development vs Production
Prerequisites
- Docker (24.x or later)
- Docker Compose (v2.20+ or Docker Desktop with Compose bundled)
- Git
Quick Start
# 1. Clone the repository
git clone https://git.crashmedia.ca/crashmedia/forwarding-manager.git
cd forwarding-manager
# 2. Create the environment configuration
cp .env.example .env
3. Generate the required secrets and edit .env:
python3 -c "import secrets; print('SECRET_KEY=' + secrets.token_hex(32))"
python3 -c "import secrets; print('ENCRYPTION_KEY=' + secrets.token_hex(32))"
# Generate a strong DEFAULT_PASSWORD (min 12 chars, uppercase + lowercase + digit)
Edit .env with the output of the commands above. At minimum you must set:
| Variable | Example |
|---|---|
SECRET_KEY |
SECRET_KEY=abc123... (64 hex chars) |
ENCRYPTION_KEY |
ENCRYPTION_KEY=def456... (64 hex chars, different from SECRET_KEY) |
DEFAULT_PASSWORD |
DEFAULT_PASSWORD=MySecurePass123 |
4. Start the application:
docker compose up -d
5. Access the application:
Open http://localhost:8080 in your browser.
Architecture
The deployment is a single monolithic container with an embedded SQLite database — no external services required.
┌──────────────────────────────────────────────┐
│ forwarding-manager │
│ ┌──────────┐ ┌────────────────────────┐ │
│ │ React │ │ FastAPI (uvicorn) │ │
│ │ Frontend│ │ Port 8000 │ │
│ └──────────┘ └───────────┬────────────┘ │
│ │ │
│ ┌─────────▼──────────┐ │
│ │ SQLite Database │ │
│ │ /data/forwarding │ │
│ │ _manager.db │ │
│ └────────────────────┘ │
└──────────────────────────────────────────────┘
│
▼
Volume: forwarding-data (/data)
✅ Preconfigured for zero external dependencies — SQLite is built in, data persists in a Docker volume, and everything works out of the box with just docker compose up -d.
PostgreSQL is still supported — If you need PostgreSQL (e.g., for high-availability or multi-replica deployments), set
DATABASE_URLin your.envfile. See Optional Variables below.
Environment Variables
Required
| Variable | Description | Generation Command |
|---|---|---|
SECRET_KEY |
Session signing key — used by the web framework to sign cookies and session data. Must be kept secret. | python3 -c "import secrets; print(secrets.token_hex(32))" |
ENCRYPTION_KEY |
Data encryption key — used to encrypt sensitive data at rest. Must be different from SECRET_KEY. |
python3 -c "import secrets; print(secrets.token_hex(32))" |
DEFAULT_PASSWORD |
Initial admin password set on first launch. Must be at least 12 characters and include uppercase, lowercase, and a digit. | N/A (choose a strong password) |
Security: Both
SECRET_KEYandENCRYPTION_KEYshould be unique per deployment. Never use the same value or commit them to version control. Rotate them if compromised.
Optional
| Variable | Default | Description |
|---|---|---|
DEFAULT_USERNAME |
admin |
Initial administrator username created on first launch. |
DATABASE_URL |
sqlite+aiosqlite:////data/forwarding_manager.db |
Full database connection URL. Defaults to embedded SQLite stored on the forwarding-data volume. Set to postgresql+asyncpg://user:pass@host:5432/dbname to use an external PostgreSQL database. |
HOST |
0.0.0.0 |
Uvicorn bind address. |
PORT |
8000 |
Uvicorn listen port. |
LOG_LEVEL |
info |
Logging verbosity (debug, info, warning, error, critical). |
ACCESS_TOKEN_EXPIRE_MINUTES |
480 |
JWT access token lifetime in minutes (8 hours by default). |
CORS_ORIGINS |
http://localhost:8080 |
Comma-separated list of allowed CORS origins. Include the scheme and port (e.g., http://localhost:8080,https://fwd.example.com). |
Volumes
| Volume | Mount Point | Description |
|---|---|---|
forwarding-data |
/data |
Application persistent data. Stores the SQLite database file and any other runtime data. |
Volumes are managed by Docker and persist until explicitly removed:
# Remove all data (irreversible!)
docker compose down -v
Ports
| Container | Container Port | Host Port (default) | Protocol | Service |
|---|---|---|---|---|
forwarding-manager |
8000 |
8080 |
TCP | FastAPI / uvicorn HTTP application |
To change the host port, edit the ports section in docker-compose.yml:
ports:
- "9090:8000" # host:9090 → container:8000
Dockerfile Overview
The Dockerfile uses a multi-stage build to produce a small, secure production image.
Stage 1: Builder (ubuntu:22.04)
- System dependencies — Installs Python 3.11 (from deadsnakes PPA), Node.js 20.x, SQLite 3, and build tools.
- Python environment — Creates a virtual environment and installs all backend Python dependencies from
backend/requirements.txt. - Frontend build — Copies the React source, runs
npm cifor deterministic installs, thennpm run buildto produce optimized static assets.node_modulesand npm cache are cleaned to minimize size. - Application code — Copies the backend source code and the
start.shentrypoint script.
Stage 2: Runtime Configuration
- Sets
EXPOSE 8000 - Configures
PATHto use the virtual environment Python - Creates a non-root user
appuserfor security - Sets the working directory to
/app - Defines the entrypoint as
/app/start.sh
Build Command
docker build -t forwarding-manager .
The build context is pruned by .dockerignore, which excludes Git metadata, Python virtual environments, node_modules, IDE files, and Docker-related files.
Entrypoint (start.sh)
The entrypoint script performs the following at container startup:
- Validates required variables —
SECRET_KEY,ENCRYPTION_KEY,DEFAULT_PASSWORDmust be set. - Defaults
DATABASE_URL— Falls back to SQLite at/data/forwarding_manager.dbif not provided. - Ensures data directory — Creates
/dataif missing and verifies write permissions. - Waits for PostgreSQL (optional) — If
DATABASE_URLcontainspostgresql://, polls the database host:port for up to 60 seconds. Skipped automatically when using SQLite. - Starts uvicorn — Launches the FastAPI application using
--factory app.main:create_app, enabling--proxy-headersfor correct operation behind a reverse proxy.
Development vs Production
Development
- Use
docker compose up -d— the application will be available onhttp://localhost:8080. - The SQLite database is persisted in the
forwarding-datavolume. - For rapid frontend iteration, run the React dev server outside Docker:
and point it at the backend atcd frontend && npm ci && npm run devhttp://localhost:8080.
Production
- Set strong secrets: Generate unique
SECRET_KEYandENCRYPTION_KEYper deployment. - SQLite is preconfigured — Suitable for single-server deployments. Data persists in the
forwarding-datavolume. - Use PostgreSQL (optional): For high-availability or multi-replica deployments, set
DATABASE_URLexplicitly. - Use a reverse proxy: Deploy nginx (or another reverse proxy) in front for SSL termination, rate limiting, and security headers. An example
nginx.confis included in the repository. - Set
CORS_ORIGINS: Restrict to your actual domain(s) to prevent unauthorized cross-origin access. - Adjust
ACCESS_TOKEN_EXPIRE_MINUTES: Lower values (e.g., 60) improve security; higher values reduce re-authentication frequency. - Database backups: Ensure the
forwarding-datavolume is backed up regularly. - Resource limits: Consider adding resource constraints to
docker-compose.yml:services: forwarding-manager: deploy: resources: limits: memory: 512M
Database Options
| Scenario | DATABASE_URL Value |
Notes |
|---|---|---|
| SQLite (default) | (not set) | Embedded database, no external dependencies |
| PostgreSQL (external) | postgresql+asyncpg://user:pass@host:5432/dbname |
For high-availability or multi-replica setups |
Files
| File | Purpose |
|---|---|
docker-compose.yml |
Service definition for the monolithic application container |
Dockerfile |
Multi-stage build for the application image |
start.sh |
Container entrypoint — validation, database setup, uvicorn launch |
nginx.conf |
Nginx reverse proxy configuration (optional, for production use) |
generate-certs.sh |
Self-signed TLS certificate generator (development) |
.env.example |
Template for required and optional environment variables |
.dockerignore |
Excludes unnecessary files from the Docker build context |