Series This post is in a series on Laravel Forge.

Starting a blog with Sculpin on Laravel Forge

Posted on December 24, 2014

Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

I recently switched The Five Minute Geek Show's web site over to Sculpin for its content management. If you're not familiar, Sculpin is a static site generator, which means I have my content and template in markdown files, which I then run a script over, and the script generates static HTML files, which I then deploy to my server. This means there's no PHP or Ruby or Python or anything serving my files; by the time they hit my web server, they're just flat HTML.

Sculpin itself has pretty great documentation, but I still wanted to provide a run-down of the steps I took to get the Five Minute Geek Show's site running in Sculpin and hosted on Forge.

Getting Sculpin running

It's best to check out the Sculpin Quick Start to get up and running, but in short, here are the commands I ran:

$ curl -O
$ chmod +x sculpin.phar
$ mv sculpin.phar ~/usr/local/bin/sculpin
$ cd ~/Sites
$ git clone fiveMinuteGeekShowBlog
$ cd fiveMinuteGeekShowBlog
$ sculpin install
$ sculpin generate --watch --server
$ cd source/_posts
  # Edit whichever files
  # Preview in browser at http://localhost:8000/
$ sculpin generate --env=prod
$ rsync -avze 'ssh -p 999' output_prod/

If you're new to Sculpin or static site generators in general, please read on. If you're not, please skip to the "Sculpin on Forge" section.

Here are the steps listed above, broken down:

1. Install Sculpin

$ curl -O
$ chmod +x sculpin.phar
$ mv sculpin.phar ~/usr/local/bin/sculpin

Our first lines are downloading the sculpin.phar executable file to our computer, marking it as executable, and then moving it into our bin directory so it's in our PATH and will be runnable from anywhere on the system (via the Terminal.) It's now installed "globally," meaning it's not just connected to a particular folder or project.

This step has been run successfully if you can spin up a new Terminal window, navigate anywhere on your computer, and run sculpin and get a positive response. If not, the issue is likely with your PATH.

2. Download a template

$ cd ~/Sites
$ git clone fiveMinuteGeekShowBlog
$ cd fiveMinuteGeekShowBlog

Sculpin can be used for a lot more than blogs, but the sculpin-blog-skeleton makes it really easy to get up and running with a Sculpin-based blog. So, we're now cloning a copy of the of the blog skeleton repository into where we keep our sites (I use ~/Sites).

3. Install Sculpin dependencies locally

$ sculpin install

sculpin install is basically a wrapper around composer install, so we're just installing our dependencies locally to this project.

4. Generate a watching server

$ sculpin generate --watch --server

sculpin generate scans the source directory and generates static files in output_dev or, if the --env ENVNAMEHERE flag is used, the output_ENVNAMEHERE folder.

NOTE: Usually you don't ever pass a --env flag. Sculpin defaults to --env=dev, and it automatically serves its previews from the output_dev folder, so you don't have to worry about that. And for prod, usually your publish script will have --env=prod and output_prod baked into them, so you won't have to think about this at all unless you're writing a publish script.

Adding the --watch flag sets it as a long-running script (like Grunt or Gulp) that watches the filesystem and auto-generates on any changes.

Adding the --server flag spins up a server at http://localhost:8000/ (you can specify the port with --port=8090) for you to check your changes at.

5. Edit files

Now you can edit, add, or delete files from anywhere in the source directory. Blog posts, in this skeleton, go in source/_posts. Check out app/config/sculpin_kernel.yml to set the URL structure for your content types, or app/config/sculpin_site.yml to change site-wide variables.

For a great example (it's the one I used) of how to modify that skeleton for Podcast web sites, check out Adam Wathan's Full-Stack Radio repository.

6. Sync up

$ rsync -avze 'ssh -p 999' output_prod/

The default prescribed method to move your files from your local site to your remote server is not git; you're saving your source in git, but you're not actually hooking up the production web site to your git repo. Rather, you're using this last line to copy the files from the output_prod folder of your local install up to the public_html (or whatever) folder on your production server.

Breaking down the rsync command

rsync -avze 'ssh -p 999' set the basic context, flags, and permissions for this rsync session.

output_prod/ shows which directory to copy from. is your username and domain for your remote server.

public_html is the remote directly it should be uploading to.

Sculpin on Forge

If you've ever used Forge before, you know it's absurdly easy to spin up a server and hook it up to a Github repo.

So, I created a new Github repo--this is not the only way to do it, but it is definitely one option--named FiveMinuteGeekShowPublic--and made it empty. I then cloned it to my ~/Sites directory.

I spun up a new site on Forge on a Linode box for, told it to pull its data from this new repo, and then set it to "Quick Deploy" (meaning, every time I push to the master branch, it runs a certain script).

I edited the Quick Deploy script to be appropriate for this site:

cd /home/forge/
git pull origin master

Then I was ready to go. I set up a publish script in my FiveMinuteGeekShow repo that generates production HTML, copies the files from Sculpin's output_prod folder over to my local FiveMinuteGeekShowPublic folder, and then git commits and pushes.

I ran chmod +x, and now I publish my blog by navigating to the fiveMinuteGeekShow directory and typing ./

Cleaner publishing

As you can tell, my publish script relies on a certain directory structure on my local machine, which is quick and easy but also a bit hacky.

You can see in Sculpin's default documentation that you can also just use rsync to copy the files directly up to your server. Check out the notes above of how your rsync command is actually structured.

You could do this with Forge. Just don't sync a Github repo, and use the credentials you were emailed when you first spun up this Forge server to set up the rsync to copy your output_prod folder up to the remote server. Same deal, and it doesn't rely on Git.

404 and nginx config

I have to thank Adam Wathan for this one. I tried to get a custom 404 page by setting error_page 404 /404/index.html in my Forge nginx configuration and discovered that it wouldn't work.

Adam helped me realize that Forge's default references to all of the .php files would override it ever hitting the 404 page, so he helped me clean up my nginx config. It ended up looking like this:

server {
    listen 80;
    root /home/forge/;
    error_page 404 /404/index.html;

    # ssl_certificate;
    # ssl_certificate_key;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

    index index.html index.htm;

    charset utf-8;

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/ error;

    location ~ /\.ht {
        deny all;

Now, any time someone visits a bad route, they'll get the 404 page.

Conch shell lusion

As you can see, wrapping your head around Sculpin--and static site generators in general--can take a minute, but once you get it, it's actually a very simple process, and hosting it on Forge is surprisingly simple.

Using Github pages or Heroku are also great options, but if you're already in the Forge space--or if you want to eventually add other functionality to the site other than just the static files being generated by Sculpin--Sculpin + Forge is a great combination.

Comments? I'm @stauffermatt on Twitter

Tags: forge  •  sculpin  •  fiveMinuteGeekShow

This is part of a series of posts on Laravel Forge:

  1. May 16, 2014 | forge, laravel, papertrail
  2. May 23, 2014 | laravel, forge, queue, beanstalkd
  3. Jun 2, 2014 | laravel, forge, cron
  4. Jun 2, 2014 | forge, laravel, ssl
  5. Jun 17, 2014 | forge, htpasswd, nginx
  6. Jun 23, 2014 | laravel, forge, subdomains
  7. Jul 9, 2014 | forge, laravel, recipes
  8. Jul 25, 2014 | laravel, forge, aws, hosting
  9. Sep 17, 2014 | laravel, forge
  10. Dec 24, 2014 | forge, sculpin, fiveMinuteGeekShow