Deploying Postorius
Introduction
Postorius is the official web-based administration interface for GNU Mailman 3, the popular open-source mailing list management software. It provides a modern, user-friendly web interface for managing mailing lists, subscribers, and list settings without requiring command-line access.
Built with Django, Postorius integrates seamlessly with Mailman 3’s REST API to provide comprehensive list management capabilities. Combined with HyperKitty (the archiver), it forms the complete Mailman 3 web suite for professional mailing list management.
Key highlights of Postorius:
- Intuitive Web Interface: Manage mailing lists through a clean, responsive web UI
- List Administration: Create, configure, and moderate mailing lists easily
- Subscriber Management: Add, remove, and manage list members with bulk operations
- Moderation Tools: Review and approve pending messages and subscriptions
- Multi-Domain Support: Manage lists across multiple domains from one interface
- User Self-Service: Allow users to manage their own subscriptions and preferences
- Integration Ready: Works with HyperKitty for complete archive management
- Open Source: Licensed under GPL v3
This guide walks through deploying Postorius on Klutch.sh using Docker alongside Mailman 3.
Why Deploy Postorius on Klutch.sh
Deploying Postorius on Klutch.sh provides several advantages:
Simplified Deployment: Klutch.sh automatically detects your Dockerfile and builds Postorius without complex configuration.
Persistent Storage: Attach persistent volumes for database and configuration data.
HTTPS by Default: Klutch.sh provides automatic SSL certificates for secure access to your admin interface.
GitHub Integration: Connect your repository directly from GitHub for automatic deployments.
Environment Variable Management: Securely store Django secret keys and database credentials.
Custom Domains: Assign a custom domain for professional list management access.
Prerequisites
Before deploying Postorius on Klutch.sh, ensure you have:
- A Klutch.sh account
- A GitHub account with a repository for your Postorius configuration
- A running Mailman 3 Core instance with REST API access
- PostgreSQL or MySQL database for Postorius
- Basic familiarity with Django applications
- (Optional) A custom domain for your Postorius instance
Understanding Postorius Architecture
Postorius consists of several components:
Django Application: The core web application providing the administration interface.
Mailman Client: Python library for communicating with Mailman 3’s REST API.
Database Backend: Stores user sessions, preferences, and cached data.
Static Files: CSS, JavaScript, and images for the web interface.
Preparing Your Repository
Create a GitHub repository containing your Dockerfile and Postorius configuration.
Repository Structure
postorius-deploy/├── Dockerfile├── settings.py├── urls.py├── wsgi.py└── .dockerignoreCreating the Dockerfile
Create a Dockerfile in the root of your repository:
FROM python:3.11-slim
WORKDIR /app
# Install system dependenciesRUN apt-get update && apt-get install -y \ gcc \ libpq-dev \ libsasl2-dev \ libldap2-dev \ libssl-dev \ && rm -rf /var/lib/apt/lists/*
# Install Python packagesRUN pip install --no-cache-dir \ postorius \ django-mailman3 \ gunicorn \ psycopg2-binary \ whitenoise
# Copy configuration filesCOPY settings.py /app/settings.pyCOPY urls.py /app/urls.pyCOPY wsgi.py /app/wsgi.py
# Create static directoryRUN mkdir -p /app/static
# Collect static filesENV DJANGO_SETTINGS_MODULE=settingsRUN python -c "import django; django.setup()" && \ django-admin collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "wsgi:application"]Creating settings.py
Create a settings.py file with your Django configuration:
import os
SECRET_KEY = os.environ.get('SECRET_KEY', 'change-me-in-production')DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '*').split(',')
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', 'django_mailman3', 'postorius', 'allauth', 'allauth.account', 'allauth.socialaccount',]
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'postorius.middleware.PostoriusMiddleware',]
ROOT_URLCONF = 'urls'WSGI_APPLICATION = 'wsgi.application'
# DatabaseDATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME', 'postorius'), 'USER': os.environ.get('DB_USER', 'postorius'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': os.environ.get('DB_HOST', 'localhost'), 'PORT': os.environ.get('DB_PORT', '5432'), }}
# Mailman API settingsMAILMAN_REST_API_URL = os.environ.get('MAILMAN_API_URL', 'http://mailman-core:8001')MAILMAN_REST_API_USER = os.environ.get('MAILMAN_API_USER', 'restadmin')MAILMAN_REST_API_PASS = os.environ.get('MAILMAN_API_PASS', '')MAILMAN_ARCHIVER_KEY = os.environ.get('MAILMAN_ARCHIVER_KEY', '')MAILMAN_ARCHIVER_FROM = ('127.0.0.1', '::1')
# Static filesSTATIC_URL = '/static/'STATIC_ROOT = '/app/static'STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# Site settingsSITE_ID = 1
# AuthenticationAUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend',]
LOGIN_URL = '/accounts/login/'LOGIN_REDIRECT_URL = '/'
# TemplatesTEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'postorius.context_processors.postorius', ], }, },]
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'Creating the .dockerignore File
Create a .dockerignore file:
.git.github*.mdLICENSE.gitignore*.log.DS_Store__pycache__*.pyc.envDeploying Postorius on Klutch.sh
- Select HTTP as the traffic type
- Set the internal port to 8000
- Detect your Dockerfile automatically
- Build the container image
- Attach the persistent volumes
- Start the Postorius container
- Provision an HTTPS certificate
Generate a Secret Key
Generate a secure Django secret key:
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"Save this key securely for the environment variables configuration.
Push Your Repository to GitHub
Initialize your repository and push to GitHub:
git initgit add Dockerfile settings.py urls.py wsgi.py .dockerignoregit commit -m "Initial Postorius deployment configuration"git remote add origin https://github.com/yourusername/postorius-deploy.gitgit push -u origin mainCreate a New Project on Klutch.sh
Navigate to the Klutch.sh dashboard and create a new project. Give it a descriptive name like “postorius” or “mailman-web”.
Create a New App
Within your project, create a new app. Connect your GitHub account if you haven’t already, then select the repository containing your Postorius Dockerfile.
Configure HTTP Traffic
In the deployment settings:
Set Environment Variables
Add the following environment variables:
| Variable | Value |
|---|---|
SECRET_KEY | Your generated Django secret key |
ALLOWED_HOSTS | your-app-name.klutch.sh |
DB_NAME | postorius |
DB_USER | your_db_user |
DB_PASSWORD | your_db_password |
DB_HOST | your_db_host |
MAILMAN_API_URL | http://your-mailman-core:8001 |
MAILMAN_API_USER | restadmin |
MAILMAN_API_PASS | your_mailman_api_password |
Attach Persistent Volumes
Add the following volumes:
| Mount Path | Recommended Size | Purpose |
|---|---|---|
/app/static | 1 GB | Static files |
/app/data | 5 GB | Application data |
Deploy Your Application
Click Deploy to start the build process. Klutch.sh will:
Run Database Migrations
After deployment, run Django migrations to set up the database:
python manage.py migratepython manage.py createsuperuserAccess Postorius
Once deployment completes, access your Postorius instance at https://your-app-name.klutch.sh. Log in with your superuser credentials to start managing mailing lists.
Managing Mailing Lists
Creating a New List
- Log in to Postorius as an administrator
- Navigate to “Mailing Lists” section
- Click “Create New List”
- Enter list name and select domain
- Configure list settings and create
Managing Subscribers
- Select a mailing list
- Go to “Membership” section
- Add or remove members individually or in bulk
- Configure member options and roles
Moderation
- Access “Held Messages” for pending moderation
- Review, approve, or reject messages
- Configure automatic moderation rules
Troubleshooting Common Issues
Cannot Connect to Mailman API
Solutions:
- Verify Mailman Core is running and accessible
- Check API URL, username, and password
- Ensure network connectivity between Postorius and Mailman
Static Files Not Loading
Solutions:
- Run
collectstaticcommand - Verify WhiteNoise is configured correctly
- Check static file paths
Database Connection Errors
Solutions:
- Verify database credentials
- Check database host accessibility
- Ensure database exists and user has permissions
Additional Resources
Conclusion
Deploying Postorius on Klutch.sh provides a modern, intuitive web interface for managing GNU Mailman 3 mailing lists. Combined with Mailman Core and HyperKitty, you have a complete, professional mailing list management solution that’s easy to deploy and maintain.