Skip to content
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

Unable to run in production #15

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

Comments

Projects
None yet
@attilagyorffy
Copy link

commented May 25, 2015

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

This comment has been minimized.

Copy link
Author

commented May 31, 2015

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Author

commented Jun 1, 2015

@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

This comment has been minimized.

Copy link
Member

commented Jun 1, 2015

@tianon

This comment has been minimized.

Copy link
Member

commented Jun 1, 2015

@attilagyorffy

This comment has been minimized.

Copy link
Author

commented Jun 1, 2015

@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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

commented Aug 9, 2015

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

This comment has been minimized.

Copy link
Member

commented Aug 14, 2015

@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

This comment has been minimized.

Copy link

commented Nov 3, 2015

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

This comment has been minimized.

Copy link

commented Jan 20, 2016

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

@AriaFallah

This comment has been minimized.

Copy link

commented Mar 2, 2016

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

commented Jan 29, 2017

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

@pascalandy

This comment has been minimized.

Copy link
Contributor

commented Aug 17, 2017

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
You can’t perform that action at this time.