Simple deploy with webhook

As these things are, my own web sites fell in quite disorganized workflow over the years. I had recently started on a new version of one and took it as clean slate opportunity.

One of the things was setting up complete automated deploy from version control.

In my case deploy goes from Bitbucket private (and gloriously free) Git repository to SiteGround GoGeek account, but much will apply to other combinations of services.

Why simple

There are many deployment tools and services around. My problem was just not getting to them, because yet another thing and don’t we really have more than enough things in webdev?

The serious deploy tools are engineered with bells and whistles. Most prominently — ability to create multiple copies of the site and switch between them.

But for simple site it can be perfectly sufficient to just commit code into version control and have it show up on server somehow. It’s not much, but it is less to deal with and can be perfectly enough.

Setup

Authentication

This is the tricky part. You might be used (I certainly am) to a common username/password workflow with version control. For automation it isn’t wise to leave your password lying around and hard to manage on top.

Instead of that Git can use cryptographic keys for authentication.

So you need to:

  1. Generate a key
  2. Add public part of key to repository
  3. Add private part of key to server

I am on Windows, so I have used PuTTY Key generator:

  • the type of key should be SSH–2 RSA
  • the public part (Public key for pasting…) goes into repository Settings > Deployment keys > Add key
  • the private part (Conversions > Export OpenSSH key) needs to be saved into file and uploaded to .ssh folder in home directory on server

I had used no passphrase for the key. I won’t be there to type it and I am told it won’t work on my shared hosting account anyway.

Now you need to have server know that the key is for working with Bitbucket. Awesome Daniel Kanchev (he was promised mention in bold) of SiteGround had worked this out for me. Edit .ssh/config in your account’s home directory and put in:

Host bitbucket.org
 HostName bitbucket.org
 IdentityFile ~/.ssh/bitbucket

Where bitbucket is the name of my private key file.

Now you should be able to clone and update private repositories on server. Note that it’s important to use the SSH format for repository link, the one that looks like git@bitbucket.org:name/repository.git

Webhook

It is now common functionality for code hosting services to have integrations with other tools. Some of those are predefined for popular things, but there is also generic option of just making POST request with information about every push to the repository.

So next piece of the puzzle is webhook — small handler that will listen to that request on our server and do a git pull whenever there is update.

I am using myWebHook, which is single PHP file, supports both GitHub and Bitbucket, and is simple to configure.

For my case:

  • myWebHook.php in the root of repository and site
  • 'master' =>  __DIR__ in configuration (add staging as needed)
  • Bitbucket repository Settings > Hooks > POST pointing to http://example.com/myWebHook.php

And now whenever you push to the repository Bitbucket will make webhook request and myWebHook will pull the respective branch on server as needed.

Security

If you have .git directory in web accessible folder, it is important that your web server doesn’t allow access to it. Or it’s a major security hole and might expose the whole source of your site.

I am using .htaccess rules from Apache Server Configs source:

<IfModule mod_autoindex.c>
Options -Indexes
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule "(^|/)\." - [F]
</IfModule>

This will prevent web access to any .git folder and anything inside of it.

Composer

And finally, since we are past days when everything was just stuffed into Git, the deploy should run Composer install for correct build.

This can probably be as simple as throwing it inside myWebHook. However I had found much nicer way with Git post-checkout hook.

The snippet will actually check composer.lock for changes and only run install if needed. Don’t forget to add --no-dev --optimize-autoloader for production targets.

Overall

Now the entirety of my deploy workflow is to commit and push changes to repository. I don’t have to run any extra tools locally or any extra services remotely.

It also makes me think more thoroughly about handling of configs and what should (not) be committed into repository. Story for another day. :)

Related Posts

2 Comments

  • So – how did you solve the ‘different configs in different environments’ problem?

    My thinking after my own experience of designing a deployment scheme is that code that’s not owned and developed by the developer doesn’t go into the main source control repo – separation of concerns.

    With that said, I do store configs that rarely change in their own little repos and pull them in with Composer. They still don’t go into the main repo that the devs are working in.

    • The current state of it is that repository has production configuration, which is overridden in development with local config file (for WP) and server configuration (for Apache).

Comments are closed.