Move your app from one server to other without downtime (for reading)

Updated: 8th September 2024
Tags: ubuntu laravel

If your database is small (< 1 GB), you can simply:

  1. php artisan down
  2. mysqldump …
  3. php artisan up

For larger websites (5 GB+ databases), follow the steps below:

So, you want to move from one server to another? But it can take time, from few minutes to hours. Or if you are going to move to other hosting provider, you will need backup database and import which can take few hours.

So what to do if you don’t wanna users to stare at black screen and search agents to fail to get pages?

If you use laravel you can block non-GET requests and show a “read-only mode” error for few minutes/hours.


If you are making a snapshot image (same provider)

  1. Turn off your server

  2. Create a full server snapshot

  3. Restore the snapshot on the new server or VM.

  4. [OLD SERVER] Add read-only middleware:
    In app/Http/Kernel.php, add the BlockPostRequest middleware to all groups (web, api, etc.).

  5. [OLD SERVER] Stop background workers (if any):

    sudo supervisorctl stop laravel-worker:*
    
  6. [OLD SERVER] Pause scheduled tasks:
    Edit crontab (crontab -e) and comment out Laravel’s scheduler:

    # * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
    
  7. After the new server installed with snapshot, update DNS records to point to the new server.

  8. Shutdown the old server once everything is verified.


If you are moving to another hosting provider (database dump)

  1. Add read-only middleware:
    In app/Http/Kernel.php, add the BlockPostRequest middleware to all groups (web, api, etc.).

  2. Stop background workers (if any):

    sudo supervisorctl stop laravel-worker:*
    
  3. Pause scheduled tasks:
    Edit crontab (crontab -e) and comment out Laravel’s scheduler:

    # * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
    
  4. Export the database:

    mysqldump -u your_user -p your_database > backup.sql
    
  5. Import the database on the new server.

  6. Update DNS records to point your domain to the new server IP.

  7. Shutdown the old server once everything is verified.


<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class BlockPostRequest
{
    /**
     * Handle an incoming request.
     *
     * @param  Request  $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        if ($request->method() !== 'GET') {
            abort(503, "Website is temporarily in read-only mode.");
        }

        return $next($request);
    }
}

Notes:


Now you can move servers without panic — users can still browse your website during the migration, and in most cases (97%), visitors don’t write anything anyway!