Fixing Ghost Docker Email Issues: A Guide to SMTP Configuration Beyond Mailgun

 

This guide is designed to help you resolve transactional email issues when running a Ghost blog via Docker. If you are struggling to get SMTP working and want to avoid the hassle of setting up Mailgun for bulk mailing, this walkthrough is for you.

Background and Problem Analysis

Ghost is a popular open-source blogging platform. When deploying Ghost with Docker, the config.production.json file typically resides at a specific path inside the container (e.g., /var/lib/ghost/config.production.json). However, because Docker containers are ephemeral by design, any manual changes made to internal files will be wiped upon container recreation. Therefore, we need a more persistent and flexible approach to configuration.

Configuration Methods Explained

  1. Using Environment Variables (Recommended)
    Ghost supports configuration via environment variables, which is ideal for Docker deployments. The official documentation, Configuration – Adapt your publication to suit your needs, notes that settings can be passed through environment variables, perfectly suiting containerized workflows.
    Implementation:
    Set your variables directly in the environment field of your docker-compose.yml file. For example:
version: "3"
services:
  ghost:
    image: ghost:5-alpine
    environment:
      url: https://yourdomain.com
      database__connection__host: mysql
      mail__transport: SMTP
      mail__options__service: "Email"
      mail__options__host: "YOUR-SERVER-NAME"
      mail__options__port: 587,465
      mail__options__auth__user: "YOUR-SMTP-ACCESS"
      mail__options__auth__pass: "PASSWORD"
      mail__options__secure: true
      mail__from: 'YOUR-SERVER-NAME'

For nested keys in config.production.json, use double underscores (__) as separators. For instance, database.connection.host becomes database__connection__host.

Benefits:

  • No need to access the container filesystem; aligns with Docker’s stateless design principles.
  • Easily managed via Docker Compose or docker run commands.
  • Environment variables take precedence over config files, making it easy to override specific settings.

Pro Tips:

  • The url field must be set to your public-facing domain (e.g., https://yourdomain.com); this is mandatory.
  • Other supported options include mail and database settings; refer to the Ghost Official Documentation – Configuration for a full list.
  • You may need to restart the container (docker-compose restart) to apply changes.

2. Mounting a Custom Configuration File via Volumes

Alternatively, you can map a local config.production.json file from your host machine into the container. Community discussions, such as Hello, Blog! – An advanced setup of Ghost and Docker made simple, suggest mounting the file directly to /var/lib/ghost/config.production.json.

  • Implementation:
    • Example docker-compose.yml:
version: "3"
services:
  ghost:
    image: ghost:5-alpine
    volumes:
      - ./config.production.json:/var/lib/ghost/config.production.json:ro

Here, ./config.production.json is the file on your host, and :ro denotes a read-only mount, ensuring the container cannot modify your host file.

Benefits:

  • Great for complex configurations or scenarios requiring strict version control of your config file.
  • Uses your host file natively upon startup, eliminating the need for excessive environment variables.

Limitations & Considerations:

  • Ensure your config.production.json is valid JSON; otherwise, the container will fail to start.
  • While early versions of the Ghost Docker image struggled with direct file mounting, recent releases (Ghost 5+) handle it seamlessly.
  • Be mindful of volume persistence; if your container is removed, ensure your config file survives.
  • Remember that environment variables take precedence over volume-mounted files.

Comparison & Recommendation

The following table summarizes the pros and cons of both methods:

Method Flexibility Ease of Use Persistence Use Case
Env Variables High High High Dynamic configuration, Production, Docker Compose
Volume Mount Medium Medium High Complex setups, Team collaboration

Based on our analysis, environment variables are the recommended choice. They align best with Docker best practices, are easier to manage in production, and provide excellent scalability. Volume mounting should be reserved for edge cases requiring total file control.

Community & Official Resources

Best Practices

  • Always prefer environment variables: Configure Ghost dynamically using the environment field in your docker-compose.yml.
  • Use volume mounts only when necessary: If you require complex overrides, mount your config file, but strictly validate the JSON syntax.
  • Always restart: After any configuration update, use docker-compose restart or docker restart <container_id>.
  • Watch the hierarchy: Environment variables override volume-mounted files; keep this in mind if you are mixing both methods.

Conclusion

For Ghost Docker deployments, managing SMTP via environment variables is the gold standard for simplicity and flexibility. Keep your setup clean, ensure your URLs are correct, and always restart your services to apply changes. Happy blogging!

Leave a Comment