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
- 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:roHere, ./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
- The official Ghost Docs – Configuration detail every option, with strong emphasis on setting the url and mail fields for production.
- Community threads like How to docker custom config.production.json highlight that while many users attempt volume mounts, environment variables remain the industry standard.
- Guides like How to Deploy a Ghost Blog With Docker advocate for the environment variable approach.
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!