Deploy a Laravel 13 Application: From Shared Hosting to Docker (2026)
Deploy a Laravel 13 Application: From Shared Hosting to Docker (2026)
When your Laravel app works locally, deployment is the next real milestone. In this guide, you will deploy Laravel 13 with MySQL 8 using three practical options: shared hosting, VPS with Docker, and Laravel Forge.
You will also get a production checklist so you avoid common mistakes like broken permissions, leaked debug pages, and queue workers not running.
Deployment options at a glance
| Option | Best for | Tradeoff |
|---|---|---|
| Shared hosting | Lowest cost MVPs | Less control, limited performance tuning |
| VPS + Docker | Full control and portability | More DevOps responsibility |
| Laravel Forge | Fastest managed VPS setup | Added platform cost |
If you are new to Laravel setup, read Create a New Laravel 13 Project in 2026 first. For config hardening, pair this with Laravel .env Explained.
Pre-deploy production checklist
Before any deployment method, confirm these baseline settings:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
LOG_CHANNEL=stack
QUEUE_CONNECTION=database
CACHE_STORE=redis
SESSION_DRIVER=redis
And run:
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan migrate --force
Key checks:
.envis not in git.storageandbootstrap/cacheare writable by the web user.- Queue workers and scheduler are configured.
- HTTPS is enabled.
Path 1: Deploy on shared hosting
Shared hosting can run Laravel if you structure files correctly.
Typical flow:
- Upload project files outside
public_html. - Point web root to Laravel
public/. - Set production
.envvalues. - Run composer install via SSH (if available).
- Run migrations and cache commands.
Recommended command set:
composer install --no-dev --optimize-autoloader
php artisan key:generate --force
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
If your host does not provide CLI access, shared hosting becomes painful quickly. In that case, move to Forge or a VPS.
Path 2: Deploy on VPS with Docker
This is ideal when you want predictable environments and full control.
1) Minimal docker-compose.yml
services:
app:
image: ghcr.io/your-org/laravel-app:latest
env_file:
- .env
depends_on:
- mysql
- redis
networks:
- app-net
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
networks:
- app-net
mysql:
image: mysql:8
environment:
MYSQL_DATABASE: laravel
MYSQL_USER: laravel
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: root-secret
volumes:
- mysql-data:/var/lib/mysql
networks:
- app-net
redis:
image: redis:7-alpine
networks:
- app-net
networks:
app-net:
volumes:
mysql-data:
2) Build and release pipeline
Use CI to build image, then pull on server.
docker compose pull
docker compose up -d --remove-orphans
docker compose exec app php artisan migrate --force
docker compose exec app php artisan config:cache
3) Queue workers and scheduler
Run queue workers using Supervisor or an extra container.
Scheduler example (cron on host):
* * * * * cd /var/www/laravel && docker compose exec -T app php artisan schedule:run >> /dev/null 2>&1
Path 3: Deploy with Laravel Forge
Forge is the fastest way to run Laravel on managed VPS infrastructure.
Core setup:
- Provision server in Forge.
- Create a site and connect your Git repo.
- Add environment variables in Forge dashboard.
- Configure deployment script.
- Enable queue worker and scheduler.
Sample Forge deploy script:
cd /home/forge/yourdomain.com
git pull origin main
composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan queue:restart
For many teams, Forge gives the best speed-to-production balance.
Zero-downtime deployment basics
Even simple apps should avoid visible downtime during deploy.
Good practices:
- Build assets before switch-over.
- Run migrations that are backward-compatible first.
- Restart workers after code deploy.
- Avoid destructive schema changes in a single release step.
If using symlink-based release directories, switch symlink only after health checks pass.
Security and reliability hardening
Minimum production hardening:
- Enable firewall (
ufw) and only allow required ports. - Disable password SSH login, use SSH keys.
- Enforce TLS certificates (LetsEncrypt).
- Back up MySQL daily and test restore.
- Use separate DB users per environment.
Monitor these metrics:
- 5xx error rate
- Queue lag
- DB CPU and slow queries
- Disk usage and backup success
Common deployment mistakes
| Mistake | Symptom | Fix |
|---|---|---|
APP_DEBUG=true in prod | Stack traces visible publicly | Set false and clear config cache |
| Missing write permissions | Logs/sessions fail | Fix owner/group and permissions |
| Not restarting workers | Old jobs run stale code | php artisan queue:restart |
| Running unsafe migrations | App errors during deploy | Use backward-compatible migrations |
| No health check route | Hard to verify release | Add /health endpoint |
Post-deploy verification checklist
After each deploy:
- Open
/healthand main app routes. - Confirm migrations succeeded.
- Confirm queue jobs process successfully.
- Check logs for exceptions in first 10 minutes.
- Confirm scheduler runs at least one cycle.
A quick smoke test after each release catches most production incidents early.
FAQ
Which deployment path should I pick in 2026?
If you want speed and less infrastructure overhead, pick Forge. If you need full control and portability, pick VPS + Docker. Use shared hosting only for small low-risk projects.
Do I need Docker for Laravel deployment?
No, but Docker improves consistency across environments and teams.
Should I run php artisan migrate --force on every deploy?
Usually yes, as part of your deployment script, as long as your migrations are safe and reviewed.
How do I avoid downtime during schema changes?
Use additive, backward-compatible migrations first, deploy code that supports both old and new schema, then clean up in a later release.
Final takeaway
Laravel deployment is easiest when you standardize your process. Pick one path, automate it, and verify every release with a checklist. In Laravel 13, consistent environment handling and safe migrations are what separate stable deployments from stressful ones.
Next in this series: How to Run Raw SQL Queries in Laravel with DB::raw and the upcoming Laravel Project Lifecycle pillar.
