Skip to content

Unable to run in production #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
attilagyorffy opened this issue May 25, 2015 · 17 comments
Closed

Unable to run in production #15

attilagyorffy opened this issue May 25, 2015 · 17 comments

Comments

@attilagyorffy
Copy link

I've been using happily the dockerfile/ghost image for quite a while but unfortunately due to some strange behaviour, I can't pull down that container anymore. This means I need to migrate to the official ghost image. I was thinking "great, now there's an official image, it must be great!" however I have to say that I'm getting disappointing results so far.

I can run a container just fine using the example commands in the README (which is for some strange reason decoupled from the actual images -- why?!) but when I am trying to run the app using the same parameters just with an extra environment variable passed down, the Ghost process quits:

attila@nl ~> docker run --name some-ghost -p 8082:2368 -d ghost
f7902e54918ef6e87fbd1102a3528328f33fa770f0fcae5718fc432ddbada79a
attila@nl ~> docker logs -f some-ghost

> ghost@0.6.3 start /usr/src/ghost
> node index

Migrations: Database initialisation required for version 003
Migrations: Creating tables...
Migrations: Creating table: posts
Migrations: Creating table: users
Migrations: Creating table: roles
Migrations: Creating table: roles_users
Migrations: Creating table: permissions
Migrations: Creating table: permissions_users
Migrations: Creating table: permissions_roles
Migrations: Creating table: permissions_apps
Migrations: Creating table: settings
Migrations: Creating table: tags
Migrations: Creating table: posts_tags
Migrations: Creating table: apps
Migrations: Creating table: app_settings
Migrations: Creating table: app_fields
Migrations: Creating table: clients
Migrations: Creating table: accesstokens
Migrations: Creating table: refreshtokens
Migrations: Populating fixtures
Migrations: Populating permissions
Migrations: Creating owner
Migrations: Populating default settings
Migrations: Complete
Ghost is running in development...
Listening on 0.0.0.0:2368
Url configured as: http://localhost:2368
Ctrl+C to shut down
^C⏎

attila@nl ~> docker run --name some-ghost-with-an-env-var -e 'NODE_ENV=production' -p 8085:2368 -d ghost
612d06f8fce241acde7d0472c2f8349b4444150813a55eac1de8fde7fa2250d4
attila@nl ~> docker logs -f some-ghost-with-an-env-var

> ghost@0.6.3 start /usr/src/ghost
> node index

ERROR: Unable to access Ghost's content path:
  EACCES, permission denied '/usr/src/ghost/content/apps/80beac6151a281d1'

Check that the content path exists and file system permissions are correct.
Help and documentation can be found at http://support.ghost.org.

I would really appreciate any help as this is getting really disappointing. There isn't any instruction in the README on how to run the app in production.

I am using docker 1.6.2 on an Ubuntu host:

docker -v
Docker version 1.6.2, build 7c8fca2

Thank you.

@attilagyorffy
Copy link
Author

I've found out what the issue was: The Ghost config.js file (here in upstream) is missing the paths configuration in production environment and gives a misleading error:

ERROR: Unable to access Ghost's content path

Actually what's happening is that the configuration directive is completely missing. This makes the issue pretty frustrating considering that we are using this software under Docker and most probably using the content path mounted to preserve data.

Not sure whether this is a Ghost issue or an issue with the Docker image where the configuration takes place, let's discuss so that we could deliver a solid and reliable solution to the problem. /CC @javorszky

@yosifkit
Copy link
Member

yosifkit commented Jun 1, 2015

Not sure if it is an oversight or on purpose, but the example config does not have any "paths" in the production section. The only thing we do is sed in the path (and the bind ip):

sed -r '
            s/127\.0\.0\.1/0.0.0.0/g;
            s!path.join\(__dirname, (.)/content!path.join(process.env.GHOST_CONTENT, \1!g;
        '

@attilagyorffy
Copy link
Author

@yosifkit well you would argue that if you redistribute a piece of software, you'd have to provide a valid config for it. This is how for example packages work on a few operating systems. I do understand that the context is different here but I think there's some overlap in terms of responsibilities.

Actually I don't see any particular config file in the Ghost repo, just an example file. Should the Docker image deal with that?

@tianon
Copy link
Member

tianon commented Jun 1, 2015 via email

@tianon
Copy link
Member

tianon commented Jun 1, 2015 via email

@attilagyorffy
Copy link
Author

@tianon I do agree that this is a fiddly issue and all I'm looking for is a solution. Given that the path directive will have to be set anyway given that it is derived of the GHOST_CONTENT env var, would you consider providing a working config in the docker image?

@gllmhyt
Copy link

gllmhyt commented Aug 1, 2015

Addressing the same issue.
Related: we cannot set the @blog.url. Clicking on the blog logo leads to the development @blog.url: http://localhost:2368/. To make it work, I have to fire up sudo (because of ownerships issues #19) and change the development URI as it was the production one.

@lethjakman
Copy link

An easy solution I've found for this is to link to your content directory manually. This obviously isn't a long term fix though. Shouldn't the $GHOST_SOURCE/content directory just always be chowned to user so that directories like content/app/ are always writable?

@yosifkit
Copy link
Member

@lethjakman, the files in $GHOST_SOURCE/content are not used at runtime, but are copied on startup into the volume at $GHOST_CONTENT and chowned. At any point before the node app starts, the user is root, so things like COPY or RUN in your own dockerfile will work just fine.

@mustafaakin
Copy link

I have modified the Dockerfile to allow production and it seems to work:

   RUN chown -R user:user /usr/src/ghost/
   CMD ["npm", "start", "--production"]

@eric-basley
Copy link

What a mess this image is absolutely unusable for production !!!!

@AriaFallah
Copy link

This works

docker run -p 2368:2368 --name ghost -- ghost /bin/bash -c 'npm start --production'

Thanks to

http://stackoverflow.com/questions/31573337/can-you-pass-flags-to-the-command-that-docker-runs

@nknapp
Copy link

nknapp commented Oct 27, 2016

First of all thanks for providing this image. Despite issue we are discussing here, this is a great help.
I was trying to provide my own config.js with a Dockerfile like this:

FROM ghost:latest
ADD config.js .

This does not work because of /entrypoint.sh overwrite this file a symlink to the config.js in the volume (/var/lib/ghost) which is initially the broken config-example.js.

@yosifkit Could you change the entrypoint such that it does not overwrite an existing config.js in the /usr/src/ghost directory?

@nknapp
Copy link

nknapp commented Oct 27, 2016

I have made my own workaround now and its working fine:

Dockerfile

FROM ghost:latest
ADD config.js config.js
ADD docker-entrypoint.sh /entrypoint.sh

docker-entrypoint.sh

Removed the whole "copy the config.js"-part

#!/bin/bash
set -e

if [[ "$*" == npm*start* ]]; then
    baseDir="$GHOST_SOURCE/content"
    for dir in "$baseDir"/*/ "$baseDir"/themes/*/; do
        targetDir="$GHOST_CONTENT/${dir#$baseDir/}"
        mkdir -p "$targetDir"
        if [ -z "$(ls -A "$targetDir")" ]; then
            tar -c --one-file-system -C "$dir" . | tar xC "$targetDir"
        fi
    done

    chown -R user "$GHOST_CONTENT"

    set -- gosu user "$@"
fi

exec "$@"

config.js

// # Ghost Configuration
// Setup your Ghost install for various [environments](http://support.ghost.org/config/#about-environments).

// Ghost runs in `development` mode by default. Full documentation can be found at http://support.ghost.org/config/

var path = require('path'),
    config;

config = {
    production: {
        url: 'https://blog.knappi.org',
        mail: {
            options: {
                host: "mail.knappi.org",
                port: 25
            }
        },
        database: {
            client: 'sqlite3',
            connection: {
                filename: path.join(process.env.GHOST_CONTENT, '/data/ghost.db')
            },
            debug: false
        },

        server: {
            host: '0.0.0.0',
            port: '2368'
        },
        paths: {
            contentPath: path.join(process.env.GHOST_CONTENT, '/')
        }
    },

    // ### Development **(default)**
    development: {
        url: 'http://localhost:2368',
        database: {
            client: 'sqlite3',
            connection: {
                filename: path.join(process.env.GHOST_CONTENT, '/data/ghost-dev.db')
            },
            debug: false
        },
        server: {
            host: '0.0.0.0',
            port: '2368'
        },
        paths: {
            contentPath: path.join(process.env.GHOST_CONTENT, '/')
        }
    }
}

module.exports = config;

This keeps the content in the volume, but the config.js in /usr/src/ghost where it is overwritten by my own custom config. And I don't have to introduce potential security weaknesses by making the /usr/src/ghostdirectory writable for user.

@eexit
Copy link

eexit commented Jan 29, 2017

Excellent, thanks @nknapp!

blog:
    container_name: blog.net
    restart: always
    image: ghost:0.11.4
    depends_on:
        - proxy
    networks:
        - nginx-proxy
    volumes:
        - /home/blog.net/content:/usr/src/ghost/content
        - /home/blog.net/config.js:/usr/src/ghost/config.js
    environment:
        NODE_ENV: production
        VIRTUAL_HOST: blog.net

@nknapp
Copy link

nknapp commented Jan 29, 2017

BTW: I have made a docker-compose setup here: https://github.com/containerize-my-server/ghost-mysql

@pascalandy
Copy link
Contributor

We had a similar conversations about Ghost V1. I propose to close this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests