Laravel Development & Deployment without Homestead or Forge

Laravel, "the PHP framework for web artisans", has dominated the PHP world in recent years – and for good reason. It has a rich feature-set that's easy to extend. Its expressive, elegant syntax is easy to read and comprehend. Taylor Otwell and all those who have contributed to the project have done a really good job.

Two of the many tools provided by Laravel are Homestead, a pre-packaged Vagrant box that provides a development environment without requiring you to install PHP, and Forge, an easily deployable PHP server pre-configured to run Laravel and other PHP applications.

Nanobox uses Docker to essentially do the same thing. It builds a fully containerized development environment on your local machine and allows you to fully customize your environment specific to your app's needs. You can then use Nanobox to deploy your locally-developed app to your cloud provider of choice.

Laravel and Nanobox

In this article, I will walk through:

  • Creating and configuring a new Laravel project with nothing installed other than Nanobox.
  • Deploying that new app to a live server on your cloud provider of choice.

Download & Install Nanobox

If you haven't already, go ahead and create a free Nanobox account, then download the Nanobox installer.

Create a New Laravel Project

Create a new project directory and cd into it.

mkdir nanobox-laravel && cd nanobox-laravel  

Add a boxfile.yml

Nanobox uses the boxfile.yml to build and configure your app's environment both locally and in production. Create a boxfile.yml in the root of your project with the following:

run.config:  
  engine: php
  engine.config:
    runtime: php-7.1
    webserver: nginx
    document_root: public
    extensions:
      - pdo
      - mbstring
      - tokenizer
      - session
      - zip
      - dom
      - xml
      - ctype
      - xmlwriter

This boxfile.yml will:

  • Provide a PHP runtime with PHP 7.1
  • Include and use Nginx as the webserver
  • Set the Nginx document root to public
  • Include PHP extensions required to install Laravel

Start Your Dev Environment

With your boxfile.yml in place, you're ready to fire up your local dev environment. Before doing so, I recommend adding a DNS alias so the running app is easy to access from a browser.

The nanobox run command will provision your dev environment, install PHP and its dependencies, run composer to install project dependencies (there won't be any on the first run), then drop you into an interactive console inside the dev environment.

# add a convenient way to access the app from a browser
nanobox dns add local laravel.dev

# start the dev environment and drop into a nanobox console
nanobox run  

Generate a Laravel Project

Inside your dev environment, use Composer to download the Laravel installer, then generate a new Laravel project.

# download the laravel installer
composer global require "laravel/installer"

# create a new laravel app
laravel new  

Nanobox mounts your local filesystem into the virtual environment, so the generated files will actually be written to your local project directory.

Start Laravel

You now have a bare-bones Laravel app ready to go. Nanobox provides the php-server helper script that starts your app using settings defined in your boxfile.yml. In this case, it will start PHP-FPM and Nginx.

# Start the app
php-server  

With the app running, you can access using the DNS Alias you added above (laravel.dev).

Default Laravel Landing Page

Hack Away!

From here, you can build out your Laravel project as you would normally. Your local codebase is mounted into the virtual environment, so any changes you make will be reflected in the running dev app.

Add a Database

Chances are that your project requires a database. Adding a database is as simple as adding a database component in your boxfile.yml and including the required PHP extensions in the list of php_extensions.

For this example, I'll install a MySQL database using MySQL 5.6. To connect to the database, I'll need the pdo and pdo_mysql extensions.

run.config:  
  # ...
  engine.config:
    php_extensions:
    # ...    
    - pdo
    - pdo_mysql

data.db:  
  image: nanobox/mysql:5.6

To apply the changes to the boxfile.yml, run the following command from the root of your project outside of Nanobox:

# Run from the root of your project, not the Nanobox console
nanobox build  

This will install the added extensions and provision a MySQL database in your dev environment.

Update Your Database Connection

Update your database connection in config/database.php to use Nanobox's auto-generated environment variables.

'mysql' => [  
    'driver' => 'mysql',
    'host' => $_ENV['DATA_DB_HOST'],
    'port' => '3306',
    'database' => 'gonano',
    'username' => $_ENV['DATA_DB_USER'],
    'password' => $_ENV['DATA_DB_PASS'],
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

I know there will be some controversy about not using the env() function and its built-in failover. I'm assuming this project will always run with Nanobox, so the failover isn't necessary. This config will work in any Nanobox environment – local, dry-run, or production. If you want to use the env() and provide default values, you're welcome to.

Adding Other Data Components

Note: The process for adding other data components such as Redis, Memcached, Postgres, etc. is the same:

  1. Add the data component to your boxfile.yml
  2. Add the necessary PHP extensions
  3. Update your connection config to use the auto-generated environment variables
  4. nanobox build to apply the changes

Getting Ready for Production

Now that your app is running locally, you're ready to deploy it to production. But before you do, there's a few things you'll need to add to your boxfile.yml.

Add a Persistent Storage Component

With Nanobox, Laravel-based components (webs and workers) can be scaled out into multi-node clusters. Because of this, you need a centralized, persistent solution for file storage.

Laravel provides a really simple integrations with Amazon S3 and Rackspace, but with Nanobox, you can stick with the local filesystem driver and use network directories.

Network directories are stored in a centralized storage component and mounted into each of your web/worker nodes. To your webs and workers, these directories appear to be part of the local filesystem, but are actually stored in the centralized filesystem of the storage component and shared between all nodes.

To include a storage component in your app, add the following to your boxfile.yml:

data.storage:  
  image: nanobox/unfs:0.9

Network directories are configured in your web component. More information about storage components is available in the Storage Guides.

Add a Web Server

In order for your app to be accessible from the public network in production, it needs a web component to act as a public endpoint.

To include a web component, add the following to your boxfile.yml:

web.site:  
  start: php-server
  writable_dirs:
    - bootstrap/cache
  network_dirs:
    data.storage:
      - storage
  log_watch:
    laravel[error]: /app/storage/logs/laravel.log

This web config will do the following:

  • Start the app with the php-server helper script
  • Make bootstrap/cache writable
  • Mount the storage directory into the storage component
  • Pipe Laravel logs into your app's unified log stream

Add Deploy Hooks

Nanobox allows you to "hook" into your app's deploy process and run commands at specific points of the process.

Because the storage directory is mounted into a separate filesystem, it will appear empty on your first deploy. Laravel needs the storage/framework/sessions, storage/framework/cache, and storage/framework/views directory to exist in order to function.

You can also run database migrations on each deploy. You can't interact with the deploy process so you need to include the --force flag with the migration command.

Add the following to your boxfile.yml to create the necessary storage directories if they don't exist and run database migrations on deploy.

deploy.config:  
  before_live:
    web.site:
      - mkdir -p storage/framework/{sessions,cache,views}
      - php artisan migrate --force

The Final boxfile.yml

If you've followed this tutorial to a "t", your boxfile.yml should look like this:

run.config:  
  engine: php
  engine.config:
    runtime: php-7.1
    webserver: nginx
    document_root: public
    extensions:
      - pdo
      - mbstring
      - tokenizer
      - session
      - zip
      - dom
      - xml
      - ctype
      - xmlwriter
      - pdo
      - pdo_mysql

web.site:  
  start: php-server
  writable_dirs:
    - bootstrap/cache
  network_dirs:
    data.storage:
      - storage
  log_watch:
    laravel[error]: /app/storage/logs/laravel.log

data.db:  
  image: nanobox/mysql:5.6

data.storage:  
  image: nanobox/unfs:0.9

deploy.config:  
  before_live:
    web.site:
      - mkdir -p storage/framework/{sessions,cache,views}
      - php artisan migrate --force

Deploy to Production

Alright, time to go live.

Add a Provider

Nanobox allows you to deploy to your cloud provider of choice. There are officially-supported hosting providers but you can also create your own custom integration using the open provider spec.

The Hosting Accounts documentation walks through linking your Nanobox account to your provider account.

Create an App

In your Nanobox dashboard, click "Launch New App", name it, select your provider and region, and go.

Deploy!

To deploy to your newly created app, you need to add it as a remote to your local project. From the root of your project, but outside the Nanobox console, run the following commands (using your app's actual name) to deploy.

# Add your app as a remote
nanobox remote add app-name

# Deploy to your app
nanobox deploy  

Nanobox will package up your code and runtime, send it up to your live servers, build the app in your live environment, and you're done!

Using Frontend Javascript Frameworks
Configure PHP with Nanobox
SSL/TLS Encryption

Scott Anderson

Designer, code-dabbler, writer, foodie, husband, and father. Core Team Member at Nanobox.

Subscribe to Nanobox

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!