# How to Dockerize a Laravel App to run in Laravel Forge


So I'm almost sure you were already in the previous blog post. If not, you might want to visit [How to deploy Docker Applications with Laravel Forge](https://blog.jpat.dev/how-to-deploy-docker-applications-with-laravel-forge).

- Note: Servers for demo purposes are now deleted, which will break URLs in the screenshots

This will be a "show by example", so let's build an App from scratch and deploy it!

### Have your application ready

Let's make a fresh Laravel Application with Sail Builder

```bash
curl -s "https://laravel.build/example-docker-forge?with=mysql,redis" | bash

cd example-docker-forge

sail up -d
```

When it finishes, you should be up and running! 🚀


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661534775194/vS4N5fI1N.png align="left")

### Let's get some more Docker magic into it!

So now, let's make this really easy, by using a package I built. Run the following commands:
```bash
composer require ijpatricio/docker-for-forge --dev

php artisan dockerEnv:install
```

It will ask you a few questions:
- `App Domain`: The host that will be registered with Traefik, routing requests from such host to that container (service).
- `App Name`  and `Vendor Name` are used to populate the `docker-compose.yml`


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661535031750/S4__iVgIp.png align="left")


For the time being, it makes a single container, with `Supervisor` (as in Laravel Sail) guaranteeing the webserver running (Nginx), the PHP interpreter (PHP-fpm), and cron (scheduling). Take into consideration using this "as-is" just with a single container. 
More complex scenarios are possible; this is keeping everything simple for the sake of understanding the basics!

I could go into details, but everything is taken care of regarding permissions so that `Laravel Forge` can read the logs in the UI, we can mount a storage folder, can run commands, and more. Maybe in another post, I could explain things further!

The build will use multiple steps, keeping the image lean. Builds frontend, installs composer dependencies, and more. The sensible basics have been covered. Customize at taste!

Also, `.env` variables can be used to change some values, but I kept things in the repo for simplicity.

Before committing the code, let's do one more thing:

```bash
mv docker-compose.yml docker-compose.dev.yml

echo "docker-compose.yml" >> .gitignore
```

This is so that each environment will use a specific `docker-compose`. For example, we locally have a database, but in production, we most likely have that service separated in another VPS.

Commit your code, let's deploy!

### On to Laravel Forge

Back on the UI, let's add a website. 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661536024450/ym_t5uSRF.png align="left")

And we should get something like this. Use your repository. Un-check "Install Composer Dependencies".

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661536156995/T5m1RMs13.png align="left")

We arrive on the `App` tab. We now change the deploy script accordingly.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661537028321/nfm_sj4S5.png align="left")

And here is the code:

```bash
cd /home/forge/example-docker-forge

git pull origin $FORGE_SITE_BRANCH

cp docker-compose.prod.yml docker-compose.yml

docker-compose build

docker-compose up -d --remove-orphans

# Run commands as `forge` user, not `root`
function forgeCmd {
    docker-compose exec example-docker-forge bash -c "gosu forge bash -c \"$@\""
}

# Run this just the first time, so it doesn't keep changing
forgeCmd "php artisan key:generate"

# add route cache, db migrate, and your other commands as you see fit!
# forgeCmd "php artisan migrate --force"
```

Check that environment variables are properly set!

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662099026410/qm8dWgQoD.png align="left")


The build can now run!

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661536743473/cwL5_0flf.png align="left")

Ta-daaaa 🚀

Logs are available from the UI:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661537135637/ElIhrBYba.png align="left")

Storage folder is mounted into the container. This app has its own instance of Redis, so no need for prefixes and so on!

And of course, our website is live, and SSL secured:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661537338817/6YQYN26zL.png align="left")

Happy coding, happy deploys 😃
