
How to Dockerize and Deploy Laravel
Lukas MauserThis Dockerfile packages your Laravel app with FrankenPHP, a modern PHP server that runs your app and serves HTTP from a single process on a single port, which is exactly what you want in a container.
If you're just here to copy and paste, here's the final Dockerfile that will produce an image for your Laravel app:
FROM dunglas/frankenphp:1-php8.3-alpine
# Grab Composer from the official image
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# Install the PHP extensions Laravel commonly needs
RUN install-php-extensions pcntl pdo_pgsql pdo_mysql gd zip intl opcache
WORKDIR /app
# Install dependencies first so this layer is cached when only source changes
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
# Copy the rest of the app and build the optimized autoloader
COPY . .
RUN composer dump-autoload --optimize
# Serve through our own Caddyfile
COPY Caddyfile /etc/caddy/Caddyfile
EXPOSE 8080
CMD ["frankenphp", "run", "--config", "/etc/caddy/Caddyfile"]
FrankenPHP is built on the Caddy web server, so it reads a small Caddyfile. Put this next to your Dockerfile:
{
frankenphp
auto_https off
}
:8080 {
root * /app/public
encode gzip
php_server
}
And here's the .dockerignore file:
vendor
node_modules
.git
.env
storage/logs/*
To build and run the image, use these commands:
docker build -t laravel-app .
docker run -p 8080:8080 laravel-app
Not just here to copy and paste? Let's go over what's happening in the Dockerfile!
The Setup
For this tutorial, I assume you have a working Laravel project. The classic way to run Laravel in production is nginx in front of PHP-FPM, which means two processes, a process manager, and a fair amount of config. Inside a container that is more moving parts than you want.
FrankenPHP replaces all of that. It is a single binary that embeds PHP and a web server, so one process serves your app on one port. That maps perfectly onto how a platform runs a container, and it is fast because the runtime stays warm between requests.
The Dockerfile
- Base image:
- Uses
dunglas/frankenphp:1-php8.3-alpine, which bundles PHP 8.3, the FrankenPHP server, and the handyinstall-php-extensionshelper.
- Composer and extensions:
- Copies the Composer binary from the official Composer image so we don't install it by hand.
- Installs common Laravel extensions. Adjust the list to match your app, for example drop
pdo_mysqlif you only use Postgres.
- Dependency installation:
- Copies only
composer.jsonandcomposer.lockfirst, then runscomposer installwithout dev dependencies. Because this happens before the rest of the code is copied, Docker can cache it and skip reinstalling packages when you only change application code.
- Application code:
- Copies the project and runs
composer dump-autoload --optimizeto generate a fast class map for production.
- Serving:
- Copies our
Caddyfile, which points the web root at Laravel'spublicfolder and enablesphp_server.auto_https offis set because your hosting platform terminates TLS for you, so FrankenPHP just needs to speak plain HTTP on port 8080.
One thing to keep in mind: Laravel reads its configuration from environment variables at runtime, so set APP_KEY, your database credentials, and the rest as environment variables on your host rather than baking a .env file into the image.
Deployment
You can deploy this Docker container to any cloud provider that supports Docker. For example, you could use platforms like Heroku, DigitalOcean, or AWS ECS. Because I am the co-founder of Sliplane, I will show you how to deploy it there.
After signing up, you can create a new service by selecting your GitHub repository. Then keep the default settings, add your environment variables such as APP_KEY and the database connection, and click deploy.

After deployment your Laravel app will be available under a subdomain of sliplane.app, usually it's just your service name.
You can also see the logs of your app, view metrics such as CPU and memory usage, add persistent storage for uploads, and much more. Whenever you push to your repository, Sliplane will automatically deploy your app.
If you want to try out Sliplane, the first 2 days are free! Try it out and let me know what you think :)
Next Steps
Once the app is running, you'll probably want to run php artisan migrate on deploy and cache your config with php artisan optimize. Both fit nicely into a small startup script. Need a hand with that, or with connecting a managed database? Feel free to reach out!
Cheers,
Lukas