Hosting Laravel apps on Hetzner SA

Warrick Bayman
4 min readAug 24, 2017

Update 2019/01/15—With only minutes to spare, Hetzner have come to the party. PHP 7.1 and 7.2 are now available as options on all shared hosting packages. I can once again recommend Hetzner as a shared hosting provider. Exciting times.

Update 2018/11/20 —I am no longer recommending Hetzner as a shared hosting provider. This is simply due to the incredibly slow response to PHP upgrades. Hetzner currently offers PHP 5.6 and PHP 7.0 both of which will reach end-of-life in December this year. There has been no indication of any intention to upgrade to at least PHP 7.1. If you MUST use shared hosting, Hetzner still provide a great service, but be warned that their PHP installation is outdated enough to be a problem.

As far as South African hosting providers go, Hetzner is pretty much up there at the top. They’re definitely not the cheapest, but you get a lot of bang for your buck.

As with most shared hosting accounts, getting Laravel to work can be a frustrating experience. Straight out of the gate, Hetzner isn’t all that different from anyone else. Their shared accounts don’t really look any different from other providers.

However, Hetzner has a secret up its sleeve: They provide SSH access to their shared hosting accounts. It is for this single reason that we direct 100% of our clients to Hetzner for hosting their websites. SSH isn’t turned on by default, but all it takes is a quick email to the support chaps to turn it on.

Updated 21/01/2018 — Hetzner is not the only provider to offer SSH access. There are a few others, but it’s generally not all that common.

Even with SSH access turned on, it’s still not all that obvious how to get Laravel up and running correctly. So I came up with a solution. Maybe there’s a better one, but for now, this works really well for me.

One small change to Laravel

Every account at Hetzner is made up of two directories. You get your account home directory, and a web directory which is then symlinked into the home directory as public_html. Because the directories are actually in different locations, Laravel needs a bit of tweaking.

I start by editing the public/index.php. I still wanted to be able to run the website in my vagrant environment, and I don’t want to break what already works. But, since Hetzner’s public directory isn’t in the same place as Laravel’s, I need to tell Laravel where to look for the application bootstrap.

If your app is running on anything less than Laravel 5.5 (You really should upgrade), then note that the autoload.php file you need is in the /bootstrap/ directory along with the app.php file. Thanks to Lyonel Zietsman for spotting that one.

This replaces the entire public/index.php file. Ideally, I wanted to change where Hetzner looked for bootstrap files based on the APP_ENV environment variable set in .env, but the problem is that none of that info is available yet. So I thought that the quickest way to check which environment I was running in was to look for the name of the Hetzner account in the current path. Since there is like ZERO chance I’d be using the same name in my dev environment, I can safely assume that strpos(__DIR__, $hetznerUsername) would only return a true value when running on Hetzner. I can then bring in vendor/autoload.php and bootstrap/app.php from the Hetzner specific location, and use a “dreaded” else to load the same files when on my dev environment.

With Laravel updated, I can push changes to my git repository.

I SSH into the Hetzner account using the default FTP details. Create a new SSH key and add it to my git account so that the Hetzner user has access to the repo. I generally like to clone into a source directory, but you can call it whatever you want…

git clone git@bitbucket.org:[repository].git source

Once the repository has been pulled in, I can grab Composer to install dependencies:

cd sourcecurl -sS https://getcomposer.org/installer | php -dallow_url_fopen=1php -dallow_url_fopen=1 composer.phar install

Hetzner allows you to change a few PHP settings through their account console. One of those options to turn on allow_url_fopen. However, I’m not fond of doing that unless really necessary, so I just specify it on the command line when I need it (that’s the -d option). Once I have the composer.phar file, I can install dependencies (again, specifying the allow_url_fopen on the command line).

You’ll also need a new .env file…

cp .env.example .env

And a new encryption key:

php artisan key:generate

The last thing I need to do is get the content of Laravel’s public directory into Hetzner’s public_html. I haven’t really found a nice way to do this. Ultimately, you would want to symlink Laravel’s public directory to the web accessible directory, but you can’t overwrite the Hetzner’s public directory (obviously), and then you wouldn’t have needed all this anyway. The simplest thing I can think to do here is to copy content of the Laravel public directory into the web accessable directory manually.

cp -r ~/source/public/. ~/public_html

That should be it.

Envoy

So to make all this just that little bit easier, I wrote a simple Envoy script. Add the following to Envoy.blade.php in the project root.

Install Envoy globally:

compser global install laravel/envoy

Now you can deploy to the Hetzner account by pushing your changes to your git repository, and running Envoy from your project root:

envoy run deploy

--

--

Warrick Bayman

Programmer, musician, cyclist (well... I own a bike), husband and father.