Start Jekyll via cron

Ubuntu 18.04LTS
Jekyll 4.0.0

I’m running a PHP script to start a Jekyll server using a cronjob:

In the cronjob, I’m switching (from root) to the user who owns the local repo directory (ubuntu) then running the script. I’m switching user because the gems live in the user’s home directory.

The script works great when I run it from the command line as ubuntu, but not from the cronjob.

I’ve got Jekyll executing from cron, but there is a problem with Ruby being able to find the required gems.

I have added the path to my gems in ubuntu’s $PATH (/home/ubuntu/gems/gems) which is where ‘pathutil’ seems to live, and executing ‘gem list’ as the ubuntu user includes ‘pathutil (0.16.2)’

I verified that the script is running as ubuntu by echo’ing whoami.

(In the root cronjob, I’m actually running one script that requires root access then passing off (&&) to the ubuntu user script, and the root script is working great … it’s this second script that’s erroring.)

First, I’m posting the cronjob, then the script, then the error message.
I appreciate any guidance. Thank you in advance.

cronjob (runs every Saturday):
* * * * 5 sudo -u ubuntu /usr/bin/php /var/www/start_jekyll.php

start_jekyll.php:
$cmd = "/home/ubuntu/gems/gems/jekyll-4.0.0/exe/jekyll serve --verbose --trace";
chdir("/var/www/jekyll-site); # owned by ubuntu
$outputfile = "/var/www/jekyll-site/joutput";
$pidfile = "/var/www/jekyll-site/jpid";
exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile)); #silent

error (as seen in /var/www/jekyll-site/joutput):
/usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in 'require': cannot load such file -- pathutil (LoadError)
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in 'require'
from /home/ubuntu/gems/gems/jekyll-4.0.0/lib/jekyll.rb:32:in '<top (required)>'
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in 'require'
from /usr/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in 'require'
from /home/ubuntu/gems/gems/jekyll-4.0.0/exe/jekyll:8:in '<main>'

It sounds like the problem might be related to PATH which you already investigated.

Can you do

sudo -u ubuntu echo $PATH

Maybe you set path in bashrc but you need to set it in another config file which gets loaded when another user switches to ubuntu. Or even do source ~/.bashrc && echo $PATH && other commands

I’d also switch to root then run the cron command manually and see if it works so you know if the problem is cron scope or your command.

I am missing context on your usecase, but I feel like cron, php and jekyll serve are not a good fit here.

If your machine restarts then cron won’t run until Saturday. And what happens if the server is already running? Then you have to manage process ID which I think you above but that’s unnecessary to manage when systems do that for you.

So rather use systemctl or another service manager to start your application on reboot and run it continuously would be a more typical flow. You can restart the service when you need to it. And it will make sure only one process is running at a time.

If you want to rebuild with jekyll weekly I’d say do the jekyll build command on a cron job.

cd path/to/repo && jekyll build --trace

And then have a server running continuously, with systemctl or apachectl using Apache or nginx or python http server. Just serving statically built files. Unless you really want some jekyll functionality maybe for debugging

Thanks, again, Michael.

sudo -u ubuntu echo $PATH
/home/ubuntu/gems/gems:/home/ubuntu/gems/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Here’s the complete use case:

  1. I’ve got Jekyll+Jekyll-Admin working for multiple sites on the same server, using a setup tweaked from that other thread, which dynamically determines available ports, and updates new site _config.yml files to use the ports. (The server name is still hard-coded into the Jekyll file, as on the other thread.)

  2. I’m also running Apache2+PHP, pointing to my main “template” directory, and I’ve built a process with a PHP form that defines things like personalization and “clones” the working directory to a new, domain-themed directory. Each of those will be used, with the CMS, to customize site content, then I will deploy them (’_site’) to the public-facing server(s).

  3. Part of the cloning process creates the virtual host file to put in nginx’s sites-available directory (and ln -s in the sites-enabled directory.) I’m using a root cronjob to copy those files and restart nginx because PHP (www-data user) doesn’t have the permissions to do it.

That script works great from both the command line (sudo php script.php) and from the cronjob.

  1. Once nginx has been restarted with the new site’s config included, I need to start Jekyll/Jekyll-Admin in the new site’s working directory in order to use the CMS.

That script works great from the command line (php start_jekyll.php), but since I need to run it after nginx has been updated and restarted, I daisy-chained the user-script into the cronjob, as above (root_script.php && sudo -u ubuntu user_script.php …)

  1. The user script uses PHP’s chdir() to cd into the new site directory, and then runs ‘jekyll serve’, as noted. Also as noted, at the top of the user script I inserted exec('whoami > /tmp/whoami') to check that, indeed, the script was executing under the ubuntu user, and it is confirmed.

The idea is to wrap all of these processes up into a single workflow, so I don’t need to manually run anything, other than to complete the PHP form and submit it, whci will create a new site that is built on Jekyll and uses the Jekyll-Admin CMS.

Everything is working great … except for starting Jekyll after the nginx restart, due to the Ruby error.

The cronjob actually runs every 2 minutes … but that seemed like a distraction for debugging purposes. I set it like that to check for new sites to set up, so I could set up new sites whenever I wanted to, and almost immediately be able to use the CMS.

The command I’m using, inside the new site top-level directory as the user who owns that directory (required because the gems are in that user’s home directory) is /home/ubuntu/gems/gems/jekyll-4.0.0/exe/jekyll serve --verbose --trace. I need to use the full path because without it, Jekyll is not found. With it, Jekyll starts, but then throws that Ruby error.