Installation Overview
This guide covers detailed installation and configuration for both development and production environments. Choose the setup that matches your needs.
Development Setup Full-featured development environment with debugging and hot reload
Production Deployment Secure, optimized production configuration with Gunicorn and PostgreSQL
System Requirements
Minimum Requirements:
Python 3.8 or higher
512MB RAM (2GB+ recommended for production)
PostgreSQL 12+ (or SQLite for development)
500MB disk space
Linux : Ubuntu 20.04+, Debian 11+, CentOS 8+, RHEL 8+
macOS : 10.15 (Catalina) or later
Windows : Windows 10/11, Windows Server 2019+
Development Installation
Step 1: Python Environment Setup
Install Python
Ensure Python 3.8 or higher is installed: Ubuntu/Debian
macOS (Homebrew)
Windows
sudo apt update
sudo apt install python3 python3-pip python3-venv
Verify installation: python3 --version
# Should output: Python 3.8.x or higher
Install PostgreSQL (Recommended)
While SQLite works for development, PostgreSQL is recommended: Ubuntu/Debian
macOS
Windows
sudo apt install postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresql
Create the database: sudo -u postgres psql
CREATE DATABASE mathsoc ;
CREATE USER mathsoc_user WITH PASSWORD 'your_secure_password' ;
GRANT ALL PRIVILEGES ON DATABASE mathsoc TO mathsoc_user ;
\q
Clone Repository
Clone the Maths Society Platform repository: git clone https://github.com/yousuf-shahzad/maths-soc-source.git
cd maths-soc-source
Step 2: Virtual Environment & Dependencies
Create Virtual Environment
Create an isolated Python environment: Linux/macOS
Windows (PowerShell)
Windows (CMD)
python3 -m venv venv
source venv/bin/activate
You’ll know the virtual environment is activated when you see (venv) in your terminal prompt.
Install Dependencies
Install all required packages: pip install --upgrade pip
pip install -r requirements.txt
Core dependencies installed:
Flask==2.1.0 - Web framework
SQLAlchemy==1.4.31 - ORM
Flask-SQLAlchemy==2.5.1 - Flask-SQLAlchemy integration
Flask-Login==0.5.0 - Authentication
Flask-Migrate==3.1.0 - Database migrations
Flask-WTF==0.15.1 - Forms and CSRF
Flask-CKEditor==1.0.0 - Rich text editor
psycopg2==2.9.3 - PostgreSQL adapter
Flask-Talisman==1.0.0 - Security headers
Flask-Limiter==3.5.0 - Rate limiting
gunicorn==22.0.0 - Production WSGI server
pytest==8.3.3 - Testing framework
Step 3: Configuration
Create a .env file in the project root:
# ===========================================
# Maths Society Platform - Development Config
# ===========================================
# Security (CHANGE THIS!)
SECRET_KEY=dev-secret-key-replace-with-random-string
# Database Configuration
DATABASE_TYPE=postgresql
DB_USERNAME=mathsoc_user
DB_PASSWORD=your_secure_password
DB_HOST=localhost
DB_NAME=mathsoc
# Alternative: Use DATABASE_URL (overrides above settings)
# DATABASE_URL=postgresql://mathsoc_user:password@localhost/mathsoc
# Environment
FLASK_ENV=development
APP_ENVIRONMENT=development
ENV=dev
# Logging
LOG_TO_STDOUT=false
# Rate Limiting (optional)
RATELIMIT_ENABLED=true
RATELIMIT_STORAGE_URI=memory://
# Server (optional)
# SERVER_NAME=localhost:5000
Configuration Options Explained
Required Settings:
SECRET_KEY: Used for session signing and CSRF tokens. Generate with:
python - c "import os; print(os.urandom(24).hex())"
Database Settings:
DATABASE_URL: Full database connection string (takes precedence)
DATABASE_TYPE: postgresql or sqlite
DB_USERNAME, DB_PASSWORD, DB_HOST, DB_NAME: PostgreSQL credentials
Environment Settings:
FLASK_ENV: development, testing, or production
APP_ENVIRONMENT: Alternative environment indicator
ENV: Another environment flag (dev, test, prod)
Logging:
LOG_TO_STDOUT: Set to true for container deployments
Rate Limiting:
RATELIMIT_ENABLED: Enable/disable rate limiting
RATELIMIT_STORAGE_URI: Storage backend (memory:// or redis://)
Step 4: Database Setup
Initialize Database Schema
Choose one of these methods: Use migrations for production-like setup: Linux/macOS
Windows (CMD)
Windows (PowerShell)
export FLASK_APP = run : app
flask db upgrade
This applies all migrations from the migrations/ directory. Quick setup with seed data: This script:
Drops existing tables (if any)
Creates fresh schema
Creates default admin user (username: admin, password: admin123)
Seeds sample data
Development only! This script drops existing data. Never use in production.
Verify Database
Check that tables were created: psql -U mathsoc_user -d mathsoc -c "\dt"
You should see tables like:
user
challenge
article
competition
submission
etc.
Step 5: Run Development Server
Start Flask
Run the development server: Output: * Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in production.
* Running on http://127.0.0.1:5000
Access Application
Open your browser to: http://127.0.0.1:5000 Login with default admin credentials:
Username: admin
Password: admin123
Change the default admin password immediately!
Production Installation
Production deployment requires:
Secure SECRET_KEY
PostgreSQL database (not SQLite)
HTTPS/SSL certificates
Gunicorn or similar WSGI server
Reverse proxy (nginx/Apache)
Proper firewall configuration
Production Environment Setup
Server Preparation
Update system and install dependencies: sudo apt update && sudo apt upgrade -y
sudo apt install python3.11 python3.11-venv python3-pip postgresql nginx -y
Create Application User
Run the application as a dedicated user: sudo useradd -m -s /bin/bash mathsoc
sudo su - mathsoc
Deploy Application
Clone and setup: git clone https://github.com/yousuf-shahzad/maths-soc-source.git /home/mathsoc/app
cd /home/mathsoc/app
python3.11 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
Production Configuration
Create production .env: # CRITICAL: Generate secure random key!
SECRET_KEY=your-production-secret-key-min-32-chars-random
# Production Database
DATABASE_URL=postgresql://mathsoc_prod:strong_password@localhost/mathsoc_prod
# Environment
FLASK_ENV=production
APP_ENVIRONMENT=production
ENV=prod
# Logging
LOG_TO_STDOUT=true
# Rate Limiting (Redis recommended for production)
RATELIMIT_ENABLED=true
RATELIMIT_STORAGE_URI=redis://localhost:6379
# Server
SERVER_NAME=yourdomain.com
Generate strong SECRET_KEY: python3 -c "import secrets; print(secrets.token_hex(32))"
Database Setup
Create production database: sudo -u postgres psql
CREATE DATABASE mathsoc_prod ;
CREATE USER mathsoc_prod WITH PASSWORD 'strong_random_password' ;
GRANT ALL PRIVILEGES ON DATABASE mathsoc_prod TO mathsoc_prod ;
ALTER DATABASE mathsoc_prod OWNER TO mathsoc_prod ;
\q
Run migrations: export FLASK_APP = run : app
flask db upgrade
Gunicorn Configuration
The platform includes gunicorn.conf.py: import multiprocessing
bind = "127.0.0.1:8000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
worker_connections = 1000
timeout = 30
keepalive = 2
# Logging
accesslog = "-"
errorlog = "-"
loglevel = "info"
# Security
limit_request_line = 4094
limit_request_fields = 100
limit_request_field_size = 8190
Test Gunicorn: gunicorn -c gunicorn.conf.py wsgi:app
Systemd Service
Create /etc/systemd/system/mathsoc.service: /etc/systemd/system/mathsoc.service
[Unit]
Description =Maths Society Platform
After =network.target postgresql.service
Requires =postgresql.service
[Service]
Type =notify
User =mathsoc
Group =mathsoc
WorkingDirectory =/home/mathsoc/app
Environment = "PATH=/home/mathsoc/app/venv/bin"
ExecStart =/home/mathsoc/app/venv/bin/gunicorn -c gunicorn.conf.py wsgi:app
ExecReload =/bin/kill -s HUP $MAINPID
KillMode =mixed
TimeoutStopSec =5
PrivateTmp =true
Restart =on-failure
RestartSec =10
[Install]
WantedBy =multi-user.target
Enable and start: sudo systemctl daemon-reload
sudo systemctl enable mathsoc
sudo systemctl start mathsoc
sudo systemctl status mathsoc
Nginx Reverse Proxy
Create /etc/nginx/sites-available/mathsoc: /etc/nginx/sites-available/mathsoc
upstream mathsoc {
server 127.0.0.1:8000;
}
server {
listen 80 ;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$ server_name $ request_uri ;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL Configuration (use certbot for Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Security Headers (Flask-Talisman handles most, but add extras)
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# File Upload Size
client_max_body_size 20M ;
# Static Files
location /static {
alias /home/mathsoc/app/app/static;
expires 30d ;
add_header Cache-Control "public, immutable" ;
}
# Proxy to Gunicorn
location / {
proxy_pass http://mathsoc;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
proxy_redirect off ;
}
}
Enable site: sudo ln -s /etc/nginx/sites-available/mathsoc /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
SSL Certificate
Install Let’s Encrypt certificate: sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Auto-renewal is configured automatically.
Database Configuration Details
The platform supports flexible database configuration through config.py:
class Config :
@ classmethod
def get_database_uri ( cls , database_name = None ):
# Prioritize DATABASE_URL environment variable
if os.environ.get( 'DATABASE_URL' ):
return os.environ.get( 'DATABASE_URL' )
# Build URI from components
db_type = os.environ.get( 'DATABASE_TYPE' , 'postgresql' )
db_username = os.environ.get( 'DB_USERNAME' , 'postgres' )
db_password = os.environ.get( 'DB_PASSWORD' , '' )
db_host = os.environ.get( 'DB_HOST' , 'localhost' )
db_name = database_name or os.environ.get( 'DB_NAME' , 'myapp' )
if db_type == 'postgresql' :
return f 'postgresql:// { db_username } : { db_password } @ { db_host } / { db_name } '
elif db_type == 'sqlite' :
return f 'sqlite:/// { os.path.join( cls . BASE_DIR , f " { db_name } .db" ) } '
Use DATABASE_URL for platforms like Heroku, Railway, or Render that provide it automatically.
Running Tests
The platform includes a comprehensive test suite:
# Run all tests
pytest
# Run with coverage
pytest --cov=app --cov-report=html
# Run specific test file
pytest tests/test_models.py
# Run with verbose output
pytest -v
Test configuration in config.py:
class TestingConfig ( Config ):
TESTING = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
WTF_CSRF_ENABLED = False
CSP_ALLOW_UNSAFE_EVAL = True
RATELIMIT_ENABLED = False
Environment Detection
The platform automatically detects the environment:
@ classmethod
def is_production ( cls ):
return os.environ.get( 'FLASK_ENV' ) == 'production' or \
os.environ.get( 'APP_ENVIRONMENT' ) == 'production' or \
os.environ.get( 'ENV' ) == 'prod'
Any of these environment variables can indicate production mode.
Monitoring & Maintenance
The platform includes built-in health checks: app/__init__.py (excerpt)
@app.route ( '/healthz' )
def healthz ():
return { "status" : "ok" }, 200
@app.route ( '/readyz' )
def readyz ():
try :
db.session.execute(text( 'SELECT 1' ))
return { "status" : "ready" }, 200
except Exception :
return { "status" : "degraded" }, 503
Monitor these endpoints: curl https://yourdomain.com/healthz
curl https://yourdomain.com/readyz
View application logs: # Systemd logs
sudo journalctl -u mathsoc -f
# Nginx logs
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
# Application logs (if LOG_TO_STDOUT=false)
tail -f /home/mathsoc/app/app.log
Automate PostgreSQL backups: # Manual backup
pg_dump -U mathsoc_prod mathsoc_prod > backup_ $( date +%Y%m%d ) .sql
# Restore
psql -U mathsoc_prod mathsoc_prod < backup_20260303.sql
Create cron job for daily backups: 0 2 * * * pg_dump -U mathsoc_prod mathsoc_prod | gzip > /backups/mathsoc_ $( date + \% Y \% m \% d ) .sql.gz
Update the application: cd /home/mathsoc/app
git pull origin main
source venv/bin/activate
pip install -r requirements.txt
flask db upgrade
sudo systemctl restart mathsoc
Security Checklist
Before going to production, verify:
Troubleshooting
Check systemd status: sudo systemctl status mathsoc
sudo journalctl -u mathsoc -n 50
Common issues:
Database connection failed (check credentials)
Port already in use (check other services)
Permission errors (check file ownership)
Missing environment variables (check .env)
Indicates Gunicorn isn’t running or nginx can’t reach it: # Check if Gunicorn is running
sudo systemctl status mathsoc
# Check if port 8000 is listening
sudo netstat -tlnp | grep 8000
# Test Gunicorn directly
curl http://127.0.0.1:8000/healthz
Database Migration Errors
If migrations fail: # Check current revision
flask db current
# Show migration history
flask db history
# Downgrade one revision
flask db downgrade
# Upgrade again
flask db upgrade
Ensure nginx has permission: sudo chown -R mathsoc:mathsoc /home/mathsoc/app/app/static
sudo chmod -R 755 /home/mathsoc/app/app/static
Check nginx configuration: sudo nginx -t
sudo systemctl reload nginx
Next Steps
Configure Your Platform Customize settings, features, and branding
Create Challenges Start adding mathematical challenges for students
User Management Add students and manage permissions
API Reference Integrate with external systems
Your Maths Society Platform is now installed and ready! Visit your domain to start using the platform.