You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Declaring content/ path as a VOLUME mount point causing problems #195
A while ago I opened this issue: #185, which was answered and closed before I had a chance to respond.
My problem is that this image prevents any modification of directories within content/, and I can't see why this is desirable or necessary. Probably I'm just being dense, but I can't work out how the proposed solution would enable me to use this image in a way that would make it possible to modify directories within content/.
Could the guidance be clarified/expanded, or, ideally, could the line declaring content/ as a fixed volume be removed? What useful purpose is it serving?
Changing the volume from within the Dockerfile: If any build steps change the data within the volume after it has been declared, those changes will be discarded.
Am I missing something? I definitely checked that page before posting. It doesn't talk much about this issue. In fact, the solutions for s3 storage adapter does not work specifically for this reason.
Install the adapter like your did. (I would add this step in the original dockerfile
You need to update your config_production.json file with the appropriate ENV.
But why do you need to move the adapter inside of ghost content? Shouldn't npm install (or yarn add) be enough for node and ghost to be able to use it? (just like the sqlite3 that gets installed in the dockerfile) Maybe it needs a gosu node npm install ghost-storage-adapter-s3 so that it is running as the correct user?
If it really needs to be in the content/storage directory, then you can just drop it in $GHOST_INSTALL/content.orig/storage and it will be placed into the volume on first start:
Now as to the content VOLUME which is the original question.
What useful purpose is it serving?
The way I understand it, the content/ of ghost is considered the mutable state of the application. Since docker does not copy the files in the image to a bind mount, we have to copy in the default files in the entrypoint. We have the volume to ensure all users don't store stuff there so that the resulting image can be used with any kind of volume for persistent storage.
This is basically the same as the WordPress image; although it has to do all of WordPress instead of just a subdirectory docker-library/wordpress#232 (comment).
But why do you need to move the adapter inside of ghost content? Shouldn't npm install (or yarn add) be enough for node and ghost to be able to use it?
This is a confusing issue to me; is this an issue with your development workflow or deploying in production? Is this in a custom docker image?
Seems like some additional advice on how to pre-seed content/plugins/config is needed in the README's and that it should be done like advised here by adding to content.orig.
This was actually a point of frustration for me when first leveraging this image -- it's not a real pleasant experience learning how this image works and will trip up people who are weak system admins.
But why do you need to move the adapter inside of ghost content? Shouldn't npm install (or yarn add) be enough for node and ghost to be able to use it?
Does this still work with v5? Is that content.orig folder is a special one that Ghost checks over regular content folder? Or do you set as your content path? (If so, what is the point here?)
I'm also having the same issue as not being able to add/change storage adapters to the projects that allready has mounted content path as volume. Added or changed storage become inside the content/adapters/storage folder of docker image, but that path is overriden by the container's volume. I feel like we need to pick specific folders inside content path those are only changed by users, like themes or images, files etc. But not the adapters folder.
I tried the approach putting adapter inside content.orig folder, but that doesn't help. In Dockerfile content.orig folder is overwritten with the content from volume. Check here:
I've just wasted an hour, trying to figure out, where I was overriding the content directory, because ghost could not find contents of my volume mounted to /var/lib/ghost...
Can we please stop with implicit definition of VOLUME $GHOST_CONTENT?
What is the point of it anyway? Why isn't /var/lib/ghost given a persistent volume, when the configuration files seem just as important as the media?
Edit:
I might be over-reacting. Maybe I don't need persistence of the configuration files, when they can be stored through ENV VARS.
I'll see if using a volume with just /content works for me and I'll come back to report.
Edit2:
I come to confirm. The implicit definition of VOLUME $GHOST_CONTENT is BAD. I would need manage a separate volume for the configuration file, because there is no other way to set things like:
@yosifkit Doesn't work for me.
I've tried setting admin__url=whatever, but it seems to not be respected by the application. I have some other difficulties with configuration. As in, setting admin url through normal configuration results in "connection refused" on the proxy. So, I am going to play around with the config a little bit more before coming up with conclusions & recommendations.
Tested it again. And it seems to work. Although I am having difficulties verifying the actual configuration, because ghost config does not dump the configuration. ghost config admin.url or whatever other syntax I tried, does not show me nested keys.
I have ran into other issues, but I am going to keep the configuration through environment variables and only use VOLUME mount for content. It is actually quite a neat approach to setting up the config on many instances.
I am still against implicit definition of content path in the config file. It leads to seemingly random volumes being created by the containers orchestrator, to which there are no ties in configurations definitions.
With anonymous volumes, default behaviour in Docker is to purge them with container removal. So, their existence is a "maybe" and a better solution would be to emphasize in introduction docs, that explicit creation of a volume for content data is important for data persistence.
Activity
pascalandy commentedon Jan 7, 2020
It's best practice to define the VOLUME in which the app is living in. Ghost lives inside /content per say.
mason commentedon Mar 26, 2020
@pascalandy then how does one modify the content of the volume(say to add s3 storage adapter)? At the moment doing this doesn't work
declaring it as volume blows out that directory. https://docs.docker.com/engine/reference/builder/#volume
pascalandy commentedon Mar 26, 2020
I don't know. But here is where you can know :)
https://ghost.org/docs/concepts/storage-adapters/
mason commentedon Mar 26, 2020
Am I missing something? I definitely checked that page before posting. It doesn't talk much about this issue. In fact, the solutions for s3 storage adapter does not work specifically for this reason.
pascalandy commentedon Mar 26, 2020
As I said, I don't use storage adapters.
My gut feeling.
Install the adapter like your did. (I would add this step in the original dockerfile
You need to update your config_production.json file with the appropriate ENV.
Have you checked on https://forum.ghost.org/ ?
yosifkit commentedon Mar 26, 2020
But why do you need to move the adapter inside of ghost content? Shouldn't
npm install(oryarn add) be enough for node and ghost to be able to use it? (just like thesqlite3that gets installed in the dockerfile) Maybe it needs agosu node npm install ghost-storage-adapter-s3so that it is running as the correct user?https://github.com/docker-library/ghost/blob/20f003a55d1b52efa436df1981852155e8f418c0/3/debian/Dockerfile#L74
If it really needs to be in the
content/storagedirectory, then you can just drop it in$GHOST_INSTALL/content.orig/storageand it will be placed into the volume on first start:https://github.com/docker-library/ghost/blob/20f003a55d1b52efa436df1981852155e8f418c0/3/debian/docker-entrypoint.sh#L10-L20
Related/duplicate of #212.
yosifkit commentedon Mar 26, 2020
Now as to the content
VOLUMEwhich is the original question.The way I understand it, the
content/of ghost is considered the mutable state of the application. Since docker does not copy the files in the image to a bind mount, we have to copy in the default files in the entrypoint. We have the volume to ensure all users don't store stuff there so that the resulting image can be used with any kind of volume for persistent storage.This is basically the same as the WordPress image; although it has to do all of WordPress instead of just a subdirectory docker-library/wordpress#232 (comment).
mason commentedon Mar 27, 2020
For anyone wondering, the following dockerfile worked for me
Docker run:
I think how it works is that the code explicitly imports from a specific directory. see here:
https://github.com/TryGhost/Ghost/blob/9d4b0c09a8061768b145a737fd0a8ec25108134d/core/server/api/v2/images.js#L1
derek-adair commentedon Jun 29, 2023
This is a confusing issue to me; is this an issue with your development workflow or deploying in production? Is this in a custom docker image?
Seems like some additional advice on how to pre-seed content/plugins/config is needed in the README's and that it should be done like advised here by adding to content.orig.
This was actually a point of frustration for me when first leveraging this image -- it's not a real pleasant experience learning how this image works and will trip up people who are weak system admins.
muratcorlu commentedon Jan 26, 2024
Does this still work with v5? Is that
content.origfolder is a special one that Ghost checks over regularcontentfolder? Or do you set as your content path? (If so, what is the point here?)I'm also having the same issue as not being able to add/change storage adapters to the projects that allready has mounted content path as volume. Added or changed storage become inside the
content/adapters/storagefolder of docker image, but that path is overriden by the container's volume. I feel like we need to pick specific folders inside content path those are only changed by users, likethemesorimages,filesetc. But not theadaptersfolder.muratcorlu commentedon Feb 2, 2024
I tried the approach putting adapter inside
content.origfolder, but that doesn't help. In Dockerfile content.orig folder is overwritten with the content from volume. Check here:https://github.com/docker-library/ghost/blob/4a77eba274347d0835dee9f8bdca17bff44f3815/5/alpine/Dockerfile#L48
So I can not update adapter. Only option that I see now is adding multiple volumes per each needed folder in
contentfolder, like:HighPriest commentedon Aug 20, 2025
I've just wasted an hour, trying to figure out, where I was overriding the
contentdirectory, because ghost could not find contents of my volume mounted to/var/lib/ghost...Can we please stop with implicit definition of
VOLUME $GHOST_CONTENT?What is the point of it anyway? Why isn't
/var/lib/ghostgiven a persistent volume, when the configuration files seem just as important as the media?Edit:
I might be over-reacting. Maybe I don't need persistence of the configuration files, when they can be stored through ENV VARS.
I'll see if using a volume with just
/contentworks for me and I'll come back to report.Edit2:
I come to confirm. The implicit definition of
VOLUME $GHOST_CONTENTis BAD. I would need manage a separate volume for the configuration file, because there is no other way to set things like:or
yosifkit commentedon Aug 20, 2025
HighPriest commentedon Aug 20, 2025
@yosifkit Doesn't work for me.
I've tried setting
admin__url=whatever, but it seems to not be respected by the application. I have some other difficulties with configuration. As in, settingadmin urlthrough normal configuration results in "connection refused" on the proxy. So, I am going to play around with the config a little bit more before coming up with conclusions & recommendations.HighPriest commentedon Aug 21, 2025
Tested it again. And it seems to work. Although I am having difficulties verifying the actual configuration, because
ghost configdoes not dump the configuration.ghost config admin.urlor whatever other syntax I tried, does not show me nested keys.I have ran into other issues, but I am going to keep the configuration through environment variables and only use VOLUME mount for content. It is actually quite a neat approach to setting up the config on many instances.
I am still against implicit definition of content path in the config file. It leads to seemingly random volumes being created by the containers orchestrator, to which there are no ties in configurations definitions.
With anonymous volumes, default behaviour in Docker is to purge them with container removal. So, their existence is a "maybe" and a better solution would be to emphasize in introduction docs, that explicit creation of a volume for
contentdata is important for data persistence.