One of the common problems when working on web apps is that you need to have a local environment that is as close as possible to the production environment. If you are working in a team it is important that you can share the local environment one way or the other too. If you only have one project it is not that big of a deal to install the needed services in the same versions as in your production environment. But as soon as you have multiple projects, chances are high that the production environments differ from project to project. And I'm not even talking about legacy projects with outdated dependencies like end-of-life PHP versions.
There are a lot of solutions which solve this problem in one way or the other. A common way is using Docker images. Docker images can be combined to provide all the services you need for your project to run. There are a lot of predefined images available at the Docker Hub for different purposes. For example Docker images with all different PHP versions, Docker images with webservers, Docker images with different database servers, Docker images with Redis and so on. As you can imagine with these already available images you can combine nearly every setup you need. But that also comes at a cost. You have to dig into a new technology and learn how you can combine and configure all the different images so that they work together and all the images can talk to each other. All you want in reality is an easy way to list what you need in which version and start developing.
That's why we choose to use Lando at Ideenreich, the company I co-founded.
Meet Lando
What exactly is Lando? Let's see how Lando describes itself:
It's a free, open source, cross-platform, local development environment and DevOps tool built on Docker container technology.
But what does this mean in practice? Basically it means that you have a .lando.yml
Yaml file in the root of your project. This file describes everything you need to run your project. From the PHP version to the webserver and the database. The advantage of this approach is that you can share this single configuration file with your team. Even better, you can add it to your version control and can ensure that everyone working on the project has the same and latest version of the file and therefore the latest environment configuration.
Another advantage of Lando is that it provides a lot of so called recipes. Recipes are predifined config files for common projects like Laravel, Symfony or Wordpress to name just a few. Every recipe contains sensible defaults for the different projects which makes the start with Lando extremely easy.
But enough of all the theory, let's get into practice and see which steps you need to take to get you Laravel project up and running locally with Lando.
Install Lando
Lando is available for macOS (10.13 or later), Windows (Windows 10 Pro+ or equivalent) and Linux systems (kernel version 4.x or higher). The only requirement is that you have Docker installed on Linux, on macOS and Windows the Lando installer will install Docker for you if needed. You can find detailed instructions on how to install Docker on Linux in the Lando docs.
You can find detailed instructions how to install Lando on your system in the docs too. On an Debian Linux for example you have to run the following two commands in a terminal.
$ wget https://files.devwithlando.io/lando-stable.deb
$ sudo dpkg -i lando-stable.deb
Setting up Lando for Laravel
The next step is to set up and configure Lando for your Laravel project.
Open a terminal, navigate to the root folder of your Laravel project and run the following command:
$ lando init --source cwd --recipe laravel --webroot public --name myapp
This command will create a basic .lando.yml
file in you project root. This file is the starting point for customizing the services and versions you want to use.
Let's quickly go through the parameters of the lando init
command.
-
--source cwd
tells Lando that the source code of your project lives in the current working directory. -
--recipe laravel
initializes the Lando file with the Laravel recipe. -
--webroot public
tells Lando which directory will be the webroot of your project. In Laravel this is typically thepublic
folder. - And with the
--name myapp
option you can define the name of your app. This is important because Lando will generate a subdomain based on the app name for you to access your project.
The generated .lando.yml
now looks like this:
name: myapp
recipe: laravel
config:
webroot: public
Looks easy, right?
At this point you can already stop and start your development environment. Simply type
$ lando start
in the terminal and Lando will bring up the whole environment. You have to make some small changes to your .env
file which I will show you later. But basically this simply Lando file is enough to start everything you need to run Laravel: A webserver and a database server.
Note: The
lando init
command has an interactive mode. If you start the command without parameters or skip parameters, it will ask for the missing information in an interactive way. Quite handy when you can't remember all of the parameters.
Customizing the environment
There are a lot of options for customizing the services and verions you want to use. You can get a good overview in the Lando docs.
But I want to show you some of the options you are most likely to use.
Setting a PHP version
Setting a specific PHP version is as easy as adding it to the config section of the .lando.yml
file:
config:
php: '7.4'
This example sets the version to PHP 7.4. The current default is PHP 7.3 for the Laravel recipe. Available are PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4 and 8.0.
Setting a composer version
If you want to set a particular composer version you can do so by adding it to the config section of the .lando.yml
:
config:
composer_version: '1.10.1'
The current default in the Laravel recipe is 2.0.7.
Choosing a webserver
By default the Laravel recipe will run an Apache 2.4. If you want to change this it again is as easy as adding it to the config section of the .lando.yml
:
config:
via: nginx:1.18
Setting a database
The default for the database is MySQL 5.7. However you can change this to MariaDB or Postgres in the config section of your .lando.yml
:
config:
database: mariadb
config:
database: postgres:9.6
Setting a caching backend
By default the Laravel recipe does not include a caching service. But you can easily add redis or memcached by adding it to the config section of the .lando.yml
file:
config:
cache: redis:2.8
config:
cache: memcached
Like for the other config options you can always request a specific version of the service.
Further customizations
There is a lot more you can configure and customize which would go to far for the scope of this post. Just to give you an idea: you can easily add xdebug to your environment:
config:
xdebug: true
There is also the option to easily add custom config files for your services like a Nginx config file or a php.ini. This can be very useful in situations where you have very special server settings you want to reproduce. You can find more on this in the Lando docs.
The Lando docs also provide a nice overview which PHP extensions are installed in which PHP version by default. You can find it here. There you can also find a guide on how to add or remove PHP extensions.
Changes in your .env file
To get your app connected to the new environment you have to make some small tweaks in your .env file.
First you have to change your DB_HOST
to database
. If you use MySQL or MariaDB Lando will create a database named laravel
for you with a user laravel
and the password laravel
. The database section in your .env
should look like this:
DB_CONNECTION=mysql
DB_HOST=database
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=laravel
If you use Postgres the settings should look like this:
DB_CONNECTION=pgsql
DB_HOST=database
DB_PORT=5432
DB_DATABASE=laravel
DB_USERNAME=postgres
DB_PASSWORD=null
Secondly you have to configure your cache driver accordingly to your settings. If you added Redis to your .lando.env
for example you have to set your REDIS_HOST
to cache
and the section should look like this:
REDIS_HOST=cache
REDIS_PASSWORD=null
REDIS_PORT=6379
The last thing you have to change is your APP_URL
. As I mentioned previously Lando will generate a subdomain for you to access your app through the browser. In our example we used myapp
as the app name. Lando will generate the domain myapp.lndo.site
for us. This works because Lando has a wildcard subdomain in their DNS for *.lndo.site which is mapped to 127.0.0.1. This means we can set our APP_URL
to this:
APP_URL=http://myapp.lndo.site
Starting Lando
Starting the whole environment is as easy as running lando start
in the root of the project. It will spin up all the needed Docker images and connect them accordingly to our config. Don't worry when you start a new project for the first time, it will take a little bit longer as all the necessary images have to be downloaded to your machine. Every further lando start will be much quicker.
When everything is started, Lando will show you a small summary of your project, the services and the available Urls. You always have the option to use the subdomain I showed you before or the localhost with an individual port. Lando shows you both options as soon as lando start
has finished. But note that the port for the localhost Url changes everytime you start the project with lando start
.
To see if everything is working, open http://myapp.lndo.site
in your browser and you should see the start page of your Laravel project.
Working with Lando
Lando has some nice commands to interact with the configured services:
lando start
: Starts the development environment and all services.
lando stop
: Stops the development environment and all servies.
lando destroy
: Destroys the whole environment and removes all images from your disk. Caution: This will also delete your database and everything inside the storage folder!
lando artisan
: Runs every artisan command inside the container, for example lando artisan migrate
to migrate your database. This is very important because if you run php artisan migrate
as you are used to, you will get an error because you can't reach the host database
which we set as the DB_HOST
in the .env
file before. Lando configured the container in a way that they can reach that host internally.
lando composer
: Runs composer commands inside the container, for example composer install
or composer add
. Again it is very important to know the difference than just running composer install
because you can have different composer version locally and in your Lando environment.
lando mysql
: Drops you inside a MySQL shell in your container.
lando php
: Runs any PHP command inside your container. Again, remember that it could be a different PHP version than you have installed locally.
lando ssh
: SSHs you inside your app container where your source code runs.
There are some useful commands for importing and exporting databases too:
lando db-export [file]
: Exports your database into a file.
lando db-import <file>
Imports a database dump into your database service.
One important thing to know: what you need to do when you make changes to your configuration inside the .lando.yml
file, in case you already started the environment at least once with lando start
. These changes have no effect because all Docker images are already downloaded and only get started on every further lando start
. But how can you change your PHP version for example? Simply make the change in the .lando.yml
file and run lando rebuild
. The whole environment will be newly created and your changes will take effect. But all your important data (the database, the storage folder) will be persistent and is still there after the rebuild.
Connecting to your database
During development you often need to take a look in the database to check things or change something manually. You can use any database client to which you are used to like DBeaver or SequelPro to connect to you database with the same credentials you used in the .env
file. This includes the host database
!
But we at Ideenreich took another approach. We have a lot of different projects and didn't want seperate connections for every project. That's why we added PHPMyAdmin to all of our projects to access the databases locally. This shows the full power of Lando as we could do that easily through the following extra lines in the .lando.yml
of our projects:
services:
pma:
type: phpmyadmin
hosts:
- database
proxy:
pma:
- pma.lndo.site
This adds a PHPMyAdmin image as an additional service, allows access to the database host and adds the pmy.lndo.site domain to proxy to that service. That means we can access the PHPMyAdmin for every project by accessing pma.lndo.site in the browser.
Conclusion
Lately there is a new option provided directly by the Laravel team, Laravel Sail. It is quite similar to Lando in many ways. The downsides are that it is for Laravel projects only where Lando can be used for any project. Also Laravel Sail is not that powerful when it comes to customizing the versions of your infrastructure. At the moment it only provides the option to switch between PHP 7.4 and PHP 8. You can of course customize anything directly via Docker and your own Dockerfiles but, as I mentioned earlier, that is something we wanted to avoid to reduce complexity.
We at Ideenreich are really happy with Lando and use it in all our projects on a daily basis since more than a year now. I hope I could show you how powerful it is.
In my opinion it provides a good layer on top of Docker and Docker Compose to easily configure an shareable environment per project.
If you have any questions about how we use Lando feel free to contact me on Twitter or by mail.