Recently, I updated my self-hosted Ghost blog from version 5 to the latest 6.6.1. After the upgrade, I faced an old challenge: making my Google AdSense ads.txt file publicly accessible. In the past, I solved this by creating a custom theme and including the ads.txt file as part of the theme’s static assets. This worked, but it meant I had to recreate a compatible theme every time Ghost released a major update.
This time, I wanted a simpler, more maintainable solution—one that didn’t require me to touch my theme or rebuild it for every new Ghost version.
The Problem: Where Does Ghost Serve Static Files?
Ghost serves static files from its theme directory, which is located inside the Docker container at /var/lib/ghost/content/themes/<theme-name>. For the default theme (like "wave" in Ghost 6.6.1), this means that if you want to serve a file like ads.txt, it needs to be present in that folder.
However, directly editing files inside the container isn’t practical for long-term maintenance. Instead, Docker lets you mount external files and folders into the container using volumes.
The Solution: Mount ads.txt as a Volume
Here’s how I solved it using Docker Compose:
volumes:
- ./ads.txt:/var/lib/ghost/versions/6.6.1/content/themes/wave/ads.txtWhat These Folders Mean:
./ads.txtis a file on your host machine containing your ads.txt content./var/lib/ghost/versions/6.6.1/content/themes/wave/ads.txtis the path inside the container where Ghost expects static files for the "wave" theme.
By mounting your local ads.txt file directly into the theme’s folder, Ghost will serve it at https://yourblog.com/ads.txt without any extra configuration.
In some cases, both of these Docker volume mappings were needed:
volumes:
- ./ads.txt:/var/lib/ghost/versions/6.6.1/content/themes/wave/ads.txt
- ./ads.txt:/var/lib/ghost/content/themes/wave/ads.txtGhost’s directory structure can vary based on how it manages versions and themes. Depending on the Docker image or how Ghost was installed, the active theme might be referenced from either:
/var/lib/ghost/versions/6.6.1/content/themes/wave/ads.txt/var/lib/ghost/content/themes/wave/ads.txt
The first path (versions/6.6.1/...) is sometimes used by Ghost’s internal version management, especially when the platform is upgraded or when running in a strict version-controlled environment. The second path (content/themes/wave/...) is the standard user-facing content directory, where themes are typically browsed or uploaded via the admin dashboard.
When Ghost serves static files like ads.txt, it resolves them relative to the currently active theme directory. If the system references either path for serving the theme, you need the ads.txt file mapped in both locations to ensure it is always accessible regardless of which one Ghost is using in your setup. This redundancy ensures no matter how Ghost references the theme, your ads.txt is available at the expected URL endpoint.
Why This Works:
- Docker’s volume mounting lets you inject files into the container at runtime.
- Ghost serves static files from the theme directory, so placing ads.txt there makes it accessible at the root.
- This approach avoids the need to create or maintain a custom theme just for ads.txt.
Conclusion
This method is simple, reliable, and doesn’t require theme customization. It’s perfect for anyone running Ghost on Docker who wants to serve static files like ads.txt without the hassle of theme management.