A Laravel application in production is four processes, not one: the web app, a queue worker, the scheduler and the databases behind them. Dokploy models each as a service in one project, builds the image from your repository on every push, and puts Traefik and a Let's Encrypt certificate in front. This guide uses a Dockerfile built on FrankenPHP (the official Laravel-friendly PHP application server with Octane support), MySQL and Redis as Dokploy database services, a second application for the queue worker and Dokploy's scheduled jobs for schedule:run. Expect twenty minutes from a fresh server.

What you need

Why a Dockerfile rather than Nixpacks

Dokploy's Railpack and Nixpacks build types detect PHP and will produce a working image for a simple app. For production Laravel you want control over the PHP version, extensions, OPcache, the web server and composer install --no-dev, so this guide uses the Dockerfile build type. The image below uses FrankenPHP, which bundles Caddy and PHP and serves Laravel directly on port 8000 without a separate Nginx and PHP-FPM pair:

FROM dunglas/frankenphp:php8.3 AS base
RUN install-php-extensions pdo_mysql redis bcmath intl zip opcache pcntl
WORKDIR /app

FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --prefer-dist --optimize-autoloader

FROM node:22-alpine AS assets
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM base
COPY . .
COPY --from=vendor /app/vendor ./vendor
COPY --from=assets /app/public/build ./public/build
RUN php artisan storage:link || true
ENV SERVER_NAME=:8000
EXPOSE 8000
CMD ["sh", "-c", "php artisan migrate --force && php artisan config:cache && php artisan route:cache && php artisan view:cache && frankenphp php-server --listen :8000 --root public"]

The dependency layers are cached between builds when only code changed, which is what keeps Dokploy builds short; a .dockerignore with node_modules, vendor, .git and storage/logs keeps the context small. Migrations run at container start with --force so each deploy applies them; remove that line if you prefer running them from a one-off job.

Step 1: databases

In a new Dokploy project create two database services: MySQL (8.x) and Redis. Set a database name, user and a generated password. Dokploy shows the internal connection details; the host is the service's internal name on the Docker network, so nothing is exposed publicly. On the MySQL service open Backups and schedule a daily dump to an S3 destination (our backup guide covers the destination setup).

Step 2: the web application

Create Service, Application. Connect the Git provider, pick the repository and branch, choose Dockerfile as the build type with the path Dockerfile and context .. In Environment, add at least:

APP_ENV=production
APP_DEBUG=false
APP_KEY=base64:...            # php artisan key:generate --show
APP_URL=https://app.example.com
LOG_CHANNEL=stderr
DB_CONNECTION=mysql
DB_HOST=<mysql service host from Dokploy>
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=...
CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=<redis service host>
REDIS_PASSWORD=...
TRUSTED_PROXIES=*

LOG_CHANNEL=stderr sends logs to the container so Dokploy's log viewer shows them; TRUSTED_PROXIES=* (or the Docker network range) lets Laravel trust Traefik's forwarded headers so url() and redirects use HTTPS. Under Domains add app.example.com with HTTPS on, certificate letsencrypt and port 8000. Deploy and watch the build log.

Step 3: the queue worker as a second application

Create another Application from the same repository with the same Dockerfile and environment variables, no domain, and override the start command in Advanced to:

php artisan queue:work redis --sleep=3 --tries=3 --max-time=3600

--max-time makes the worker exit hourly so Docker's restart policy gives you a fresh process with the latest code after deploys. Scale the worker's memory in your head: 100 to 300 MB each. If you use Horizon, run php artisan horizon instead and expose its dashboard behind the web app's auth.

Step 4: the scheduler

Dokploy's Schedule Jobs run a command in a service's container on a cron expression. Add one on the web application with * * * * * and the command php artisan schedule:run. That replaces the system crontab entry Laravel's docs ask for, and it survives redeploys because it targets the service, not a container ID.

Step 5: files, sessions and the things that bite later

Deploying on push, previews and rollbacks

Enable Auto Deploy on the web application and Dokploy registers a webhook with your Git provider; every push to the branch builds and deploys. Preview Deployments give each pull request its own environment on a generated domain, useful for Blade and Livewire changes that need a human look. Rollbacks are one click in the Deployments tab. Scale beyond one server later by adding a build server (so Composer and npm run elsewhere) or a Swarm worker; both need a container registry, covered in the multi-node guide.

Frequently Asked Questions

Can I deploy Laravel on Dokploy without writing a Dockerfile?

Yes. Choose the Railpack or Nixpacks build type; both detect PHP and Composer and produce a working image with a built-in server. Set the start command to php artisan serve --host=0.0.0.0 --port=8000 and the domain port to 8000. For production the Dockerfile in this guide gives you OPcache, the exact PHP version and extensions, and cached dependency layers.

How do I run Laravel migrations on Dokploy?

Either at container start, as this guide’s Dockerfile does with php artisan migrate --force, or as a Dokploy scheduled job or a one-off command from the service’s terminal tab. The start-time approach runs them on every deploy and is the usual choice; keep a database backup schedule so a bad migration is recoverable.

What does hosting a Laravel app on Dokploy cost?

Dokploy is free; the MassiveGRID Starter preset (2 vCPU, 4 GB RAM, 64 GB NVMe) that runs the app, a queue worker, MySQL and Redis is $9.58 a month on shared cores or $19.80 on dedicated cores. Laravel Forge adds a per-server fee on top of the server and Vapor bills per request; here the server is the whole bill.

Dokploy hosting from $9.58 a month

A MassiveGRID VPS preset for Dokploy: 2 vCPU, 4 GB RAM and 64 GB NVMe for $9.58 a month on shared cores or $19.80 on dedicated cores, in New York, London, Frankfurt or Singapore, on a Proxmox HA cluster with Ceph storage, a 100% uptime SLA and a 15-day money-back guarantee. Run the one-line installer yourself or open a ticket and we install Dokploy for you.

Configure a Dokploy server

Further Reading