I’ve been noodling on a few ideas and didn’t put any into markdown because manually running the jekyll build and pushing to my web server required me to be near the right computer and have a few minutes of really boring stuff. I never got around to using GitHub Actions when it was in beta, but figured I would give it a try so I would never have to think about spending time working on building out new posts. I think I have it set up so all I have to do is push out commit to GitHub and a few seconds later, stuff zips over to my host.

What I wanted to automate

I used a shared hosting service that’s great. For like $30 a year, I get a cpanel site that lets me run pretty much anything low resource that runs on unix and doesn’t require root. It’s pretty convenient, but I can’t shell into it and it’s a multi-tenant environment with probably thousands of other sites.

I was previously ftping stuff manually with FileZilla using FTP over TLS so there’s an encrypted channel. My host doesn’t have a server certificate just for my domain so while I connect to ftp.prepend.com, the cert doesn’t have any subjectAltNames. This wasn’t a problem manually as I just accepted the cert’s fingerprint and moved on.

I just wanted to run the jekyll build and then ftp everything over in a non-interactive manner. And trigger that whenever I pushed something to master.

Exploring Actions

I searched for a decent tutorial and read through a GitHub’s blog post and browsed the action marketplace, but I was confused because I just wanted to run the equivalent of:

gem install bundler
bundle install
bundle exec jekyll build
ftp _site ftp.prepend

Trying to find examples of people doing this led me to some helpful folks who build actions like BryanSchuetz/jekyll-deploy-gh-pages and SamKirkland/FTP-Deploy-Action. I have a little bit of not liking the idea of pulling someone’s package into my build script that has access to delete everything on my web’s public_html and a little of wanting to learn how to use GitHub Actions, so I didn’t want to use an external action, although I’m sure they’re fine.

Going through the workflow syntax let me figure out how to structure my workflow. I’m used to the really extensive GitLab CI docs, so while GitHub’s stuff has a nicer stylesheet it wasn’t really as thorough as I’d like.

It’s pretty cool that GitHub has a free tier for actions. For free accounts, we get 20 total concurrent jobs, or 5 concurrent MacOS jobs. My blog is currently a private repo, so I’m limited to 500MB of storage and 2000 runner minutes per month. I’m not sure what takes up storage. Checking my account settings show that I’m using 0MB of 1GB and that I have 3,000 minutes. So that’s a bonus above GitHub’s documentation. What’s interesting is that GitHub charges a “minute multiplier” where windows runners charge double minutes and mac runners charge 10x minutes. I’m interested in how expensive it must be to run windows as I’m sure GitHub is under pressure to highlight Microsoft stuff and it’s still twice as expensive to run as linux.

It looks like my total pipeline takes about 3 minutes to run, so as long as I’m under 300 posts a month, I should be safe in the free zone. I like that GitHub sets a $0 limit so that stuff stops rather than exceed my budget. I wish AWS and Azure did that. Needless to say, I picked their ubuntu runner over windows or mac.

Comically, when I was testing with sftp and scp, I had a pipeline time out at 6 hours.

Picking an ftp client

My host uses user names and passwords and doesn’t allow ssh, so I tried to find a tool that I could get working on my test environment, my macbook air. I couldn’t get SCP or SFTP working after fiddling with them for an hour or so, so I ended up using LFTP simply because it was the only client tool I could get to work non-interactive to my host, with it’s ssl cert, and with the userids it issues. My host includes an at symbol so my log in is something like “foo@bar.com” instead of just “foo.”

Monkeying with my wwwroot directory structure

Prepend.com is my main domain and cpanel doesn’t let me set up a custom directory. I have a few other sites I run that are subdirectories under public_html so I was worried about accidentally deleting the other sites while mirroring my blog builds. I tried to set up a new directory under public_html just for the blog, but couldn’t point prepend.com’s web site to that directory. I found some instructions but they required shell and root so I couldn’t try them.

I contemplated creating a blog.prepend.com subdomain and redirecting any requests to prepend to the subdomain, but that seemed like it would eventually cause errors in the future. And I’d hate for people to have to waste typing and looking at those five extra characters.

I eventually decided to just backup the entire public_html and be extra careful.

Actually writing the steps

Once I finished testing locally, I was able to actually write the yaml workflow and it looked pretty much like this:

    runs-on: ubuntu-latest

      - uses: actions/checkout@v1
      - name: list
        run: ls -alrt
      - name: install ruby
        run: |
          sudo apt install ruby-full
          ruby --version
      - name: install lftp
        run: |
          sudo apt-get install lftp
          lftp --version
      - name: jekyll build
          JEKYLL_ENV: production
        run: |
          echo "$JEKYLL_ENV"
          sudo gem install bundler
          sudo bundle install
          sudo bundle exec jekyll build
          ls -alrt
      - name: test secrets
        run: |
          echo bananas
          echo $
      - name: update web site
        run: |
          lftp -d -e "set ssl:verify-certificate false; mirror -R -v --overwrite --no-perms ./_site /; bye" -p $ -u "$","$" $

I’ve got too much printing out and logging than needed, but I’ll leave it in for the first few runs to see is anything wonky happens.


Overall, I like Actions and mostly like the direction GitHub is going with their whole “let’s empower developers and earn karma through freemium.” I’m suspicious that it’s a bait and switch and they’ll eventually take this away. It that happens, I can always run this in my own container, it will just be more work. I’ve got an old synology that can theoretically run owncloud. I’m kind of interested in indieweb principles so I don’t want to lock into any particular platform or technology. I prefer approaches that can be ported easily. This approach still depends on git, ruby, github, markdown, and html. But as long as the output is just html then it can be moved across to any http server. I can live with that and not worry too much about having too much lock in.

Future explorations

I am curious to see what the logs look like for Windows and Mac, so I want to switch the build runner around a bit to see how they do mac and windows.

I guess I also don’t have the exist of blocking on the boring deployment and can now let inspiration flow.