This section documents the CI/CD workflow for ForwardEmail's self-hosted solution, explaining how Docker images are built, published, and deployed.
- Overview
- CI/CD Workflow
- Deployment Process
- Maintenance Features
- Versioning
- Accessing Images
- Contributing
ForwardEmail's self-hosted solution uses GitHub Actions to automatically build and publish Docker images whenever a new release is created. These images are then available for users to deploy on their own servers using the provided setup script.
Note
There is also our self-hosted blog and self-hosted developer guide
And for the more broken down step-by-step versions see the Ubuntu or Debian based guides.
The self-hosted Docker image build and publish process is defined in .github/workflows/docker-image-build-publish.yml. This workflow:
- Triggers: Automatically runs when a new GitHub Release is published
- Environment: Runs on Ubuntu with Node.js 18.20.4
- Build Process:
- Checks out the repository code
- Sets up Docker Buildx for multi-platform builds
- Logs into GitHub Container Registry (GHCR)
- Updates the schema for self-hosted deployment
- Builds the Docker image using
self-hosting/Dockerfile-selfhosted - Tags the image with both the release version and
latest - Pushes the images to GitHub Container Registry
# Key workflow steps
name: Build and Publish Self-Hosted Docker Image
on:
release:
types: [published] # Trigger on new releases
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
# Setup steps...
# Build and publish Docker image
- name: Build / Publish Docker image to GitHub Container Registry
run: |
IMAGE_NAME=ghcr.io/${{ github.repository }}-selfhosted:${{ github.ref_name }}
docker build -f self-hosting/Dockerfile-selfhosted -t $IMAGE_NAME .
docker tag $IMAGE_NAME ghcr.io/${{ github.repository }}-selfhosted:latest
docker push $IMAGE_NAME
docker push ghcr.io/${{ github.repository }}-selfhosted:latestThe Docker image is built using a multi-stage approach defined in self-hosting/Dockerfile-selfhosted:
-
Builder Stage:
- Uses Node.js 20 as the base image
- Sets
SELF_HOSTED=trueenvironment variable - Installs dependencies with pnpm
- Builds the application in production mode
-
Final Stage:
- Uses a slimmer Node.js 20 image
- Installs only the necessary system dependencies
- Creates required directories for data storage
- Copies the built application from the builder stage
This approach ensures the final image is optimized for size and security.
Users can deploy the self-hosted solution using the provided setup script:
bash <(curl -fsSL https://raw.githubusercontent.com/forwardemail/forwardemail.net/refs/heads/master/self-hosting/setup.sh)This script:
- Clones the repository
- Sets up the environment
- Configures DNS and firewall settings
- Generates SSL certificates
- Pulls the latest Docker images
- Starts the services using Docker Compose
The docker-compose-self-hosted.yml file defines all the services required for the self-hosted solution:
- Web: Main web interface
- API: API server for programmatic access
- SMTP: Email sending service
- IMAP/POP3: Email retrieval services
- MX: Mail exchange service
- CalDAV: Calendar service
- CardDAV: Contacts service
- MongoDB: Database for storing user data
- Redis: In-memory data store
- SQLite: Database for storing emails
Each service uses the same Docker image but with different entry points, allowing for a modular architecture while simplifying maintenance.
The self-hosted solution includes several maintenance features:
Users can enable automatic updates that will:
- Pull the latest Docker image nightly
- Restart services with the updated image
- Log the update process
# Setup auto-updates (runs at 1 AM daily)
0 1 * * * docker compose -f /path/to/docker-compose-self-hosted.yml pull && docker compose -f /path/to/docker-compose-self-hosted.yml up -d >> /var/log/autoupdate.log 2>&1The setup provides options for:
- Configuring regular backups to S3-compatible storage
- Backing up MongoDB, Redis, and SQLite data
- Restoring from backups in case of failure
SSL certificates are automatically managed with options to:
- Generate new certificates during setup
- Renew certificates when needed
- Configure DKIM for email authentication
Each GitHub Release creates a new Docker image tagged with:
- The specific release version (e.g.,
v1.0.0) - The
latesttag for the most recent release
Users can choose to use a specific version for stability or the latest tag to always get the newest features.
The Docker images are publicly available at:
ghcr.io/forwardemail/forwardemail.net-selfhosted:latestghcr.io/forwardemail/forwardemail.net-selfhosted:v1.0.0(example version tag)
No authentication is required to pull these images.
To contribute to the self-hosted solution:
- Make changes to the relevant files in the
self-hostingdirectory - Test locally or on an ubuntu based VPS using the provided
setup.shscript - Submit a pull request
- Once merged and a new release is created, the CI workflow will automatically build and publish the updated Docker image