Simple Deploy

Table of Contents

This is a simple deploy process for static HTML files. There’s a lot of people who have written about this approach. Here’s my take. Incidentally, this is how this blog is deployed. You could also modify the process to deploy projects that use a server, which I’ll talk about that at the end.

The only thing you need is git. And once you get it set up, you can deploy with a git push. For things such as a personal website (like this one), it’s perfect. I don’t need to hand out permissions to the deploy process, or run quality control processes. I just want something easy to use, fast, free (as in cost), and unlikely to break or require maintenance.

Spoiler: We do this by setting up a “bare git repository” on our server with a post-receive hook. It’s a one liner, it looks like this:

GIT_WORK_TREE=~/ git checkout -f

For those familiar with git you may know exactly what I’m talking about, and be able to take it from here. For those who need step by step instructions, read on.

In the following when I say “laptop” I’m assuming you’re running Mac, Linux, or some other *nix. When I say “server” I mean Linux. This will probably work on Windows using git-bash but no gaurantees, as I haven’t tested.

Ok. Let’s get started.

Make Sure Git is Installed

Open a terminal on your laptop and try running the command git. If you get “command not found”, install it by following instructions here.

Create a Git Repository For Your Project

If you don’t already have your files in a git repository, it’s easy (and free) to create one. A typical project has source files that you edit, and generated files that you deploy. We want to check both of these into git. If you’re directly editing HTML/CSS/JS, then that’s more like having just the generated side of things - that’s fine, just check in what you have. You can see for example the files I have checked in for the Hugo blog that you’re reading right now.

So go to the directory where your files are, making sure it has everything you would need to work on the project. Then type git init. If you now type git status it will tell you that you’re in a new repository, you haven’t added any files yet, and it will list out all the files/folders in the directory and indicate them as “new”. Type git add . and git commit -m "initial commit". Now if you type git status you should see “nothing to commit, working tree clean”. If not, check for errors in the previous commands. I can’t think of any snags you could run into at this point, so if you do then contact me.

Purchase Web Hosting

You’ll need to look up instructions specific for your webhost. I can’t tell you exactly what you need to do, but typically the process involves:

  1. Set up an account with some hosting provider
  2. Purchase a domain (.com’s are usually ~$10/year)
  3. Set up hosting for the domain (shared hosting is usually ~$10/month for as many sites as you want)

When you set up the hosting in step 3, it’s going to ask you what directory you want to serve the files from. This is a directory on the webhosts server, and will generally be under the home directory of a user account that belongs to you. Note the file path that you are serving the website from. Typically this will be user/domain, so for me it is ~/ (tilde means “my home directory”). Now if your project directory has a place for generated files, like a public directory, then you will want to host the files from user/domain/public. It’s going to be an empty directory for now, but later on you will be configuring this as your destination for files to be deployed to.

Set Up SSH Keys

I’ll tell you how I do this. If you want more warnings about security and the proper way to do things, check here.

  1. On your laptop open a terminal.
  2. Check to see if you already have SSH keys by typing ls .ssh. If you have then skip to step 4.
  3. Type ssh-keygen and press enter three times. You should be back at your normal prompt, and it should have drawn a box with ascii characters. Note: this is opting for no password on your key files. If your laptop gets hacked, your website gets hacked. Which was probably true anyway.
  4. Type cat .ssh/ and copy the text that’s output.

Ok, now for the server.

  1. SSH into your remote server. The command you type should look like ssh All linux based web hosting should support this. Check your admin panel, you might have to create a new user and set a password.
  2. If you’ve already set up your key as trusted, you’ll get in without being prompted for a password, and you can skip to the next section. If you’re asked for your password then enter it and continue to step 3.
  3. Ok, remember the that we copied in step 4 on your laptop? We’re going to use that now. Try ls .ssh to make sure you have a .ssh directory. If it’s not there, you can use the ssh-keygen to generate the files with the appropriate permissions.
  4. Edit the .ssh/authorized_keys file and paste the contents of your clipboard. You can do that with Vim like so: vim .ssh/authorized_keys. Press i for insert mode. Right click your mouse and paste. Press esc. Type :wq (for write & quit) and press enter. Sheesh. Why would anybody use Vim?
  5. Type chmod 600 .ssh/authorized_keys and press enter.
  6. The server should be configured to let us in without a password now. Log out of the server by pressing ctrl+D, then press the up arrow to recall your previous command (ssh and press enter to run it. Were you logged in without a password?

If it’s not working, the most common culprits for troubleshooting are:

  • You missed some characters when pasting your public key file, or you got some additional characters in there. This could include endlines or white space. A proper key entry should start with ssh-rsa and end with the hostname that it was generated on user@computer. It should have a single endline after that. If there are multiple keys in your authorized_hosts then each one needs to be separated by a single endline.
  • The permissions on the .ssh directory should be 700, and most of the files in there should be 600 with the exception of public keys, which should be 644. This is true of both your laptop and the server. If any of the file permissions are wrong, SSH tends to not fail silently, which can be frustrating.
  • In some rare cases the SSH daemon may be configured to always require a password, or to prefer other authentication schemas. There are other non standard configurations. Typically this won’t be the case unless you yourself set it up that way, or if you’re playing in someone else’s sandbox.
  • SSH daemon might not be running on the remote computer. If that were the case you wouldn’t have gotten in in step 1. This is typically only the case if you set up the computer yourself. All standard web hosts are going to have an SSH daemon running.

Create a Bare Git Repository on Your Server

SSH into your webserver. This should be quick and passwordless since you set up your SSH keys above.

Typically on a server, I put all my git repositories in a folder called git in my home directory. So let’s say you bought the domain, you would type mkdir -p git/ From now on when I say just fill in whatever domain you bought. Next type cd git/ Then type git init --bare. Now this is a magical git command that most people using git have never used before. People pay for repositories for good reason mostly - the access controls, pull requests, review process, and integrations are very nice and productive. But did you know you can set up a server with a single command? I was impressed the first time I did this. And it still impresses me. What a beautiful program. Thank you Linus!

Create a Post-Receive Hook To Deploy Your Files

Now comes the real magic. Git supports “hooks” which let you run a command of your choice whenever an event of your choice is detected. The hook we are interested in today is the post-receive hook. This gets run whenever the remote server receives new files.

Please edit git/ I’ll tell you how to do it in vim, but please use the editor of your choice.

  1. Type vim git/
  2. press i for insert
  3. Copy and paste the following:
GIT_WORK_TREE=~/ git checkout -f
  1. Note: the GIT_WORK_TREE above needs to be set to the same directory that your website is serving files from. We set that up in the first step “Purchase Web Hosting” above. So double check your configuration if you need to.
  2. Press esc then :wq and enter to save the file and exit.

That’s it for the server setup!

Push Some Changes to Test

Come back to your laptop, in the directory where your project lives. You committed your files earlier, so now:

  1. git remote add deploy
  2. git push deploy master

You should see some output indicating that your files are being pushed, and the post-receive hook is being executed. When that’s done, go to in your browser and see if your site shows up.

If not… SSH into your server and check the website directory. Did the files get deployed there? Go to the git directory and type git log. git log --stat will show you files modified, and git log -p will show you exact line by line changes. Were your pushes received? See if you can follow the chain of events and find the place where it has broken down.

  1. You wrote code on your laptop.
  2. Typed (approximately) git add, git commit, git push
  3. The server should have received the push, run the post-receive, deployed the files to the web directory.
  4. When you visited in your web browser, the website displayed whatever files it found at the configured location

One of the most common mistakes I make is not properly selecting the directory my website needs to serve files from. Make sure it is the public directory, or where ever your generated files are ending up.

Also if you have a .gitignore make sure your generated files are not being exempted. If they are, they won’t get transferred! Many people prefer not to check in generated files. If that’s you, you’ll have to get creative and run some additional commands in the post-receive hook to generate the files server side. But that also means that your build tools will have to be installed on the server. In my preferred process I choose not to do that, because I find it simpler if I only have to install those tools on my laptop. Installing software on shared hosting can be difficult, or forbidden entirely.


Does that seem like a lot? It probably does if these tools are new for you. And I’ve tried to explain the concepts from a beginner’s perspective. From my perspective I use Vim, SSH, and Git every day. This process takes me no more than a half hour from beginning to end. The steps are so familiar to me because I use them in many other workflows as I’m developing, troubleshooting, and configuring software. And I was going to do most of these steps anyway… setting up the webhost, setting up SSH. So it’s really just the git setup that is added for me, and that’s minor. So I think the sweet spot for this process will be if you find synergy with your other tasks. If you’re not using these tools now, maybe getting your website deployed will be motivation to learn them, and then you’ll find yourself using them for many other things. I hope this process and these tools serve you well, as they have for me.

Modifying This Process for a Dynamic Website

You can deploy dynamic websites in this way as well. The one thing that’s going to be different is that in your post-receive hook, you will have some additional commands to run depending on your programming language of choice. I won’t go through all the options here, but Python, Ruby, Node.js, Go… will all have their own specific commands to reboot a web service.

Will you be able to run a dynamic website on shared hosting? Historically the answer was no, unless the site was written in PHP. Now some hosting providers are supporting other languages, so if yours does your life may be a little bit easier. If not, you’ll need to look at purchasing a Virtual Private Server (VPS) and spending some extra cash. Or look into more modern container based hosting or serverless webhooks. Containers and serverless will probably use a different process from what is described here - but you may find some clever way to combine the two.

If you plan to use shared hosting or a VPS, then this process should work. One piece of advice I will give you is to use your operating system’s (or shared host’s) built in facilities for running a service. A dynamic site requires that your process be kept running on the server all the time. These service facilities will automatically reboot it if it crashes, or if the server restarts. And the commands you will run will differ based on what software you used. On Ubuntu the standard service runner can be restarted with service foo restart. Or your shared hosting might support passenger, in which case you would call passenger-config restart-app foo. You will want to add a command that looks like that in your post-receive, after the files had been updated. But configuring services is beyond the scope of this guide.

If it were up to me, I would typically deploy dynamic sites using a container based hosting, or using a service like Heroku. There are many complications to running stateful software that don’t come up with a static site like we’ve described here. Containers are the state of the art way to do that, and handle scalability and high availability in a way that takes a lot of work to achieve if you’re working with VMs and manually configuring servers. Heroku was using containers before we had a word for containers. So the benefits to their architecture are for most of the same reasons.

That’s it for me. Hope you find it helpful. Best of luck to you! Deploy something cool, so the world can see it!

Brandon Mason avatar
Brandon Mason
Brandon looks at the world with wonder, curiosity, compassion, and creativity. He is interested in the different perspectives that we as human beings hold, and finding ways to co-exist and co-create our future.
comments powered by Disqus