Backup Ubuntu site / Laravel Forge server with Tarsnap

Would you like to backup your Ubuntu server with Tarsnap and also backup your Mysql database? Then follow this steps:

Install Tarsnap

1. Install dependencies

sudo apt-get install build-essential ext2fs-dev zlib1g-dev libssl-dev 

2. Install Tarsnap

Download Tarsnap with this wget:

wget --no-check-certificate https://www.tarsnap.com/download/tarsnap-autoconf-1.0.35.tgz

Now we need to extract, configure, and compile Tarsnap.

tar xfz tarsnap-autoconf-1.0.35.tgz
cd tarsnap-autoconf-1.0.35
./configure
sudo make install clean

3. Configure Tarsnap

Copy the example config to the live config:

sudo mv /usr/local/etc/tarsnap.conf.sample /usr/local/etc/tarsnap.conf

Then create a key, save this key to a USB or something, you can’t reset it.

mkdir ~/.tarsnap
tarsnap-keygen --keyfile /home/youruser/.tarsnap/tarsnap.key --user your@email.com --machine your-machine-name
You’ll be prompted for your Tarsnap password when running tarsnap-keygen.

Now, edit the tarsnap.conf file:

sudo pico /usr/local/etc/tarsnap.conf

Point the keyfile directive to the key file we created a couple steps ago. The top of your tarsnap.conf file should look similar to this now:

### Recommended options
 
# Tarsnap cache directory
cachedir /tmp/tarsnap-cache
 
# Tarsnap key file
keyfile /home/youruser/.tarsnap/tarsnap.key

4. Use Tarsnap to Make a Backup

To create a backup do this:

tarsnap -c -f servername-20140805 /home/forge

I’m using Laravel forge’s home directory. This directory is now backup up to Tarsnap. In the next step we’ll add a backup folder with the latest mysql-database.

Backup Mysql database

Create a folder in /home/forge : backup. Create a file in the folder:

touch /home/forge/makebackup.sh

Insert this information in the file:

#!/bin/sh
TODAY=$(date "+%A");
flock -n ~/.mysqldump mysqldump -u forge -p forge --password=YOURPASSWORD > ~/backup/mysql-latest.sql; 
flock -n ~/.tarsnap.lock tarsnap -c -f "$(uname -n)-$(date +%Y-%m-%d_%H-%M-%S)" ~/ 2>/dev/null; 

Create Cronjob

Let the makebackup.sh be called every x days:

crontab -e

Insert this piece of info:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO={{YOUREMAILHERE}}
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 2 * * * flock -n ~/.makebackup.lock ~/backup/makebackup.sh

To view the backupped files so far:

tarsnap --list-archives | sort

Thanks to Longren.io and thanks to Hypernode

Laravel 5: simple multi-tenant/multi-site model setup (many-to-many relation covered as well)

Laravel multi site multi tenant navigation bar illusatrationLaravel 5 is a brand new version of the popular framework. Unfortunately, there are no good multi-tenant setups for Laravel 5 yet. That’s why I’d decided to create my own simple version as well, based on Eloquent Global Scopes.

In my case I wanted a sites table, with categories that have a many to many relationship. So like:

sites
id | name

categories
id | name

site_category
id | site_id | category_id

So this table structure is a many to many relation. With this setup you can create a multi-site setup with different categories. Site A has categories 1 and 2, Site B has category 3 etc. It’s defined in the model as follows:

App\Site.php

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Site extends Model {

    protected $fillable = ['name', 'domain'];

    public function categories()
    {
        return $this->belongsToMany('App\Category', 'site_category');
    }
}

And the category like:

App\Category.php

<?php namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Traits\TenantableTrait;

class Category extends Model {
	use TenantableTrait;

	/**
	 * The fillables
	 * @var array
	 */
	protected $fillable = ['name', 'description'];

	/**
	 * A category has many sites
	 */
	public function sites()
    {
        return $this->belongsToMany('App\Site', 'site_category');
    }

Notice that this category has the trait TenantableTrait assigned. That is like:

App\Traits\TenantableTrait.php

<?php namespace App\Traits;

use App\TenantScope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;

trait TenantableTrait {

    /**
     * Boot the tenantable trait for the model
     *
     * @return void
     */
    public static function bootTenantableTrait()
    {
        static::addGlobalScope(new TenantScope);
    }

}

And finally, don’t forget the global Eloquent scope:

App\TenantScope.php

&lt;?php namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ScopeInterface;
use Session;

class TenantScope implements ScopeInterface
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        if (Session::has('siteId'))
        {
            $siteId = session('siteId');
          
            $builder->whereHas('sites', function($query) use($siteId)
            {
                $query->where('sites.id', $siteId);
            });
        }
    }

    /**
     * Remove the scope from the given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function remove(Builder $builder, Model $model)
    {
        
        dd('remove called');
    }
}

Now, if you set the site id by session (e.g.) in a controller with:

Session::set('siteId', 1)

A all categories that have a site_category link with site_id=1 will be called. As you see, the remove method still has to be specified, so if you’d like to finish up this script, leave it in the comments.

You can repeat this with site_products or probably even site_category_product (with some finetuning, if that works, let me know below 🙂 ).