Skip to content
ThorMail

Installation

ThorMail is self-hosted software that you deploy on your own infrastructure. This guide covers installation using Docker (recommended) or manual setup.

Before proceeding, please ensure you meet the following requirements. ThorMail is a powerful tool that requires some system administration knowledge to run effectively.

  • Docker Recent version
  • Docker Compose Recent version
  • PostgreSQL 18 (with pg_partman extension recommended) - We provide an optimized image: thormail/postgres-thormail
  • Redis 6+ (for caching and rate limiting) or compatible in-memory database
  • Valid Email (for admin account setup)

To ensure a smooth deployment, you should be familiar with:

  • Docker & Docker Compose: Managing containers, volumes, and understanding logs.
  • Networking: Configuring reverse proxies, DNS, and firewalls.
  • Linux Environment: Basic command line usage and environment variables.

For a super fast setup, you can use our installation script. This script handles the download of the Docker Compose file and basic configuration.

The installation script will automatically download the necessary Docker Compose files and generate random, secure environment variables for your instance. Simply follow the on-screen prompts to complete the setup.

Terminal window
# Download the install script
curl -fsSL https://thormail.io/install.sh -o install.sh
# Run the installer
bash install.sh

The fastest way to get ThorMail running is with Docker Compose.

  1. Create docker-compose.yml

    Create a file named docker-compose.yml with the following content:

    Use this for a complete, self-contained installation where all components (Database, Backend, Frontend, Worker) run on the same server.

    docker-compose.yml
    version: '3.8'
    
    services:
     postgres:
       image: thormail/postgres-thormail:latest
       pull_policy: always
       environment:
         POSTGRES_USER: ${DB_USER}
         POSTGRES_PASSWORD: ${DB_PASSWORD}
         POSTGRES_DB: ${DB_NAME}
       volumes:
         - thormail_postgres_data:/var/lib/postgresql/data
       networks:
         - thormail_network
       restart: unless-stopped
    
     redis:
       image: docker.dragonflydb.io/dragonflydb/dragonfly
       networks:
         - thormail_network
       restart: unless-stopped
    
     backend:
       image: thormail/thormail-backend:latest
       pull_policy: always
       environment:
         PORT: 4000
         DB_HOST: ${DB_HOST}
         DB_PORT: ${DB_PORT}
         DB_USER: ${DB_USER}
         DB_PASSWORD: ${DB_PASSWORD}
         DB_NAME: ${DB_NAME}
         REDIS_HOST: ${REDIS_HOST}
         REDIS_PORT: ${REDIS_PORT}
         JWT_SECRET: ${JWT_SECRET}
         ENCRYPTION_KEY: ${ENCRYPTION_KEY}
         EMAIL: ${EMAIL}
       ports:
         - "4000:4000"
       volumes:
         - thormail_backend_extensions:/app/extensions
       depends_on:
         - postgres
         - redis
       networks:
         - thormail_network
    
     frontend:
       image: thormail/thormail-frontend:latest
       pull_policy: always
       environment:
         NUXT_PUBLIC_API_BASE: ${NUXT_PUBLIC_API_BASE}
       ports:
         - "3000:3000"
       depends_on:
         - backend
       networks:
         - thormail_network
    
     worker:
       image: thormail/thormail-worker:latest
       pull_policy: always
       environment:
         DB_HOST: ${DB_HOST}
         DB_PORT: ${DB_PORT}
         DB_USER: ${DB_USER}
         DB_PASSWORD: ${DB_PASSWORD}
         DB_NAME: ${DB_NAME}
         JWT_SECRET: ${JWT_SECRET}
         ENCRYPTION_KEY: ${ENCRYPTION_KEY}
         WORKER_ID: ${WORKER_ID}
         WORKER_NAME: ${WORKER_NAME}
       volumes:
         - thormail_worker_extensions:/app/extensions
       depends_on:
         - postgres
       networks:
         - thormail_network
    
    networks:
     thormail_network:
       driver: bridge
    
    volumes:
     thormail_postgres_data:
     thormail_backend_extensions:
     thormail_worker_extensions:
  2. Configure environment variables

    Create a .env file in the same directory:

    .env
    ################################################################################
    # DATABASE CONFIGURATION
    ################################################################################
    
    # Database hostname (service name in Docker Compose)
    DB_HOST=postgres
    
    # PostgreSQL port
    DB_PORT=5432
    
    # Database username
    DB_USER=thormail
    
    # [GENERATED SECURELY] Database password
    DB_PASSWORD=generating...
    
    # Database name
    DB_NAME=thormail
    
    
    
    ################################################################################
    # REDIS CONFIGURATION
    ################################################################################
    
    # Redis hostname (service name in Docker Compose)
    REDIS_HOST=redis
    
    # Redis port
    REDIS_PORT=6379
    
    
    ################################################################################
    # SECURITY & ENCRYPTION
    ################################################################################
    
    # [GENERATED SECURELY] Secret key for signing JSON Web Tokens
    JWT_SECRET=generating...
    
    # [GENERATED SECURELY] 32-char key for encrypting sensitive data
    ENCRYPTION_KEY=generating...
    
    
    ################################################################################
    # GENERAL CONFIGURATION
    ################################################################################
    
    # Owner Email - Must match your ThorMail license email
    EMAIL=[email protected]
    
    # Frontend API URL - Where the frontend reaches the backend
    NUXT_PUBLIC_API_BASE=http://localhost:4000
    ################################################################################
    # WORKER CONFIGURATION
    ################################################################################
    
    # [GENERATED SECURELY] Unique ID for this worker node
    WORKER_ID=generating...
    
    # Human readable name for this worker
    WORKER_NAME=worker-1
    

    Security Note: The values above are securely generated in your browser each time you refresh using crypto.getRandomValues(). They are not stored or transmitted anywhere. You can safely copy and use them for your production `.env` file.

    Required Changes: You must update the following variables to match your environment:

    • EMAIL: Needs to match the owner email address associated with your ThorMail license.
    • NUXT_PUBLIC_API_BASE: The URL where the frontend (browser) can reach the backend.
      • Localhost: http://localhost:4000
      • Server IP: http://<YOUR_SERVER_IP>:4000 (if accessing remotely without a domain)
      • Domain: https://api.yourdomain.com (if using a reverse proxy/domain)
  3. Start the services

    Terminal window
    docker compose up -d
  4. Access ThorMail

    Open http://localhost:3000 in your browser.

For production deployments where you want to orchestrate containers individually.

We recommend using our optimized Docker image which comes pre-configured with PostgreSQL 18 and pg_partman.

Create a persistent volume for the database data (required for data persistence):

Terminal window
docker volume create thormail_postgres_data

Then run the container:

docker run -d \
--name thormail-postgres \
--restart unless-stopped \
-e POSTGRES_USER=thormail \
-e POSTGRES_PASSWORD=secure_password \
-e POSTGRES_DB=thormail \
-v thormail_postgres_data:/var/lib/postgresql/data \
-p 5432:5432 \
thormail/postgres-thormail:latest

ThorMail consists of four main components:

ComponentPurposePort
Backend APIREST API, authentication, queue management4000
FrontendWeb dashboard for configuration and monitoring3000
WorkerMessage processing, adapter execution-
DatabasePostgreSQL 18 with pg_partman for queue and data5432
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Your App │────▶│ Backend │────▶│ PostgreSQL │
└─────────────┘ │ API │ │ (Queue) │
└─────────────┘ └──────┬──────┘
┌─────────────┐ │
│ Worker(s) │◀────────────┘
└──────┬──────┘
┌────────────┼────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ SendGrid│ │ SMTP │ │ Twilio │
└─────────┘ └─────────┘ └─────────┘

When ThorMail starts for the first time, it automatically creates the initial administrator account using the EMAIL address defined in your configuration. For security, a random password is generated and displayed in the backend logs.

Since ThorMail runs several processes via PM2, search for the thormail-master logs within the backend container.

To see the initial setup message and generated password, run:

Terminal window
docker logs thormail-backend

You will see a message similar to this:

🔐 FIRST USER SETUP REQUIRED
No users found in the database.
Initial admin user created with: [email protected]
A random password has been generated for your security.
Admin Password: [SOME_RANDOM_PASSWORD]

To quickly extract only the password from your logs, you can run:

Terminal window
docker logs thormail-backend 2>&1 | grep "Admin Password:"

After installation, verify everything is working:

  1. Check Backend Health

    Terminal window
    curl http://localhost:4000/health
  2. Check Worker Status

    • The worker should appear in the dashboard under “Workers”
  3. Activate License

    • Go to Settings → License
    • Enter your license key

Your ThorMail installation is ready! Continue to the Quick Start Guide to send your first message.