May 17, 2025
Deploying Laravel Inertia to Coolify using Docker Compose (with and without SSR)
In this comprehensive guide, we’ll walk through the process of deploying a Laravel application with Inertia to Coolify using Docker Compose. We’ll cover both Server-Side Rendering (SSR) and non-SSR setups, allowing you to choose the best option for your project.
Prerequisites
Before we begin, make sure you have the following:
- A Laravel application with Inertia set up
- A Coolify server set up
Step 1: Prepare Your Docker Configuration
First, we need to create a Dockerfile and a docker-compose.yaml file in the root of your Laravel project.
Dockerfile
Create a Dockerfile with the following content:
FROM dunglas/frankenphp:php8.4 AS base
RUN install-php-extensions \
pdo_pgsql \
redis \
zip \
gd \
mbstring \
exif \
bcmath \
opcache \
intl \
pcntl
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get install -y \
curl \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y nodejs \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV SERVER_NAME=:80
FROM base AS builder
WORKDIR /app
COPY . .
RUN composer install --no-dev --optimize-autoloader --no-interaction
RUN npm ci && npm run build
# If you're using SSR, use this instead
# RUN npm ci && npm run build:ssr
FROM base AS production
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
WORKDIR /app
COPY . .
COPY --from=builder /app/vendor /app/vendor
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/public/build /app/public/build
COPY --from=builder /app/bootstrap/ssr /app/bootstrap/ssr
RUN php artisan optimize && \
chown -R www-data:www-data /app/storage /app/bootstrap/cache
docker-compose.yaml
Create a docker-compose.yaml file with the following content:
services:
app:
build:
context: .
dockerfile: Dockerfile
image: laravel
container_name: laravel-app
restart: unless-stopped
working_dir: /app
volumes:
- storage:/app/storage
depends_on:
- db
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1/up"]
interval: 2s
timeout: 10s
retries: 10
labels:
- "traefik.http.middlewares.ipwhitelist.ipwhitelist.sourcerange=0.0.0.0/0,::/0"
- "traefik.http.middlewares.add-forwarded-headers.headers.customrequestheaders.X-Forwarded-For=X-Real-IP"
- "traefik.http.middlewares.upload-limit.buffering.maxRequestBodyBytes=67108864"
# Uncomment the following block if you're using SSR
# ssr:
# image: laravel
# container_name: laravel-ssr
# restart: unless-stopped
# command: ["php", "/app/artisan", "inertia:start-ssr"]
# volumes:
# - storage:/app/storage
# depends_on:
# - app
# healthcheck:
# test: ["CMD", "curl", "-f", "http://127.0.0.1:13714/health"]
# interval: 2s
# timeout: 10s
# retries: 10
scheduler:
image: laravel
container_name: laravel-scheduler
restart: unless-stopped
command: ["php", "/app/artisan", "schedule:work"]
volumes:
- storage:/app/storage
depends_on:
- app
db:
image: postgres:18
container_name: laravel-db
restart: unless-stopped
environment:
POSTGRES_DB: ${DB_DATABASE}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- dbdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}"]
interval: 5s
timeout: 20s
retries: 10
If you’re not using SSR, keep the ssr service commented out. If you are using SSR, uncomment the ssr service block.
Step 2: Create Additional Configuration Files
.dockerignore
Create a .dockerignore file in the root of your project:
/.phpunit.cache
/bootstrap/ssr
/node_modules
/public/build
/public/hot
/public/storage
/resources/js/actions
/resources/js/routes
/resources/js/wayfinder
/storage/*.key
/storage/pail
/vendor
.DS_Store
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/auth.json
/.fleet
/.idea
/.nova
/.vscode
/.zed
.git
.gitignore
.gitattributes
.github
/tests
README.md
CHANGELOG.md
docker-compose*.yaml
Dockerfile*
.dockerignore
Thumbs.db
Step 3: Prepare Your Laravel Application
- If you’re using SSR, modify your
config/inertia.phpto match the Docker configuration:
<?php
return [
'ssr' => [
'enabled' => true,
// Modify it to this
'url' => env('INERTIA_SSR_URL', 'http://ssr:13714'),
// 'bundle' => base_path('bootstrap/ssr/ssr.mjs'),
],
'testing' => [
'ensure_pages_exist' => true,
'page_paths' => [
resource_path('js/pages'),
],
'page_extensions' => [
'js',
'jsx',
'svelte',
'ts',
'tsx',
'vue',
],
],
];
- Modify your
app/Providers/AppServiceProvider.phpto force HTTPS in production:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
public function boot(): void
{
// Add this
if ($this->app->environment('production')) {
URL::forceScheme('https');
}
}
}
This change ensures that all URLs generated by your application in production will use HTTPS.
- Modify your
bootstrap/app.phpto trust proxies:
<?php
use App\Http\Middleware\HandleAppearance;
use App\Http\Middleware\HandleInertiaRequests;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Middleware\AddLinkHeadersForPreloadedAssets;
use Illuminate\Http\Request;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// Add this
$middleware->trustProxies(
at: '*',
headers: Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB
);
$middleware->encryptCookies(except: ['appearance', 'sidebar_state']);
$middleware->web(append: [
HandleAppearance::class,
HandleInertiaRequests::class,
AddLinkHeadersForPreloadedAssets::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
This change ensures that all URLs generated by your application in production will use HTTPS.
Step 4: Deploy to Coolify
- Log in to your Coolify dashboard.
- Connect your Git repository to Coolify.
- Create a new project and select “Docker Compose” as the deployment method.
- In the Coolify project settings, make sure to set the following environment variables:
APP_ENV: Set this toproductionDB_HOST: Set this todbDB_DATABASE: Your database nameDB_USERNAME: Your database usernameDB_PASSWORD: Your database password- Any other environment-specific variables your application needs
.env
- Configure the deployment settings:
- Set the container name
- Set the domain name
- Set the following post-deployment command:
This command will create a symbolic link fromphp artisan storage:linkpublic/storagetostorage/app/public.
- Save your configuration and deploy your application.
Step 5: Post-Deployment Tasks
After successful deployment, go to the Command tab. Execute the following command:
php artisan migrate --force
This command will run your database migrations, ensuring your database schema is up to date.
Conclusion
You have now successfully deployed your Laravel Inertia application to Coolify using Docker Compose, with options for both SSR and non-SSR setups. This configuration provides a scalable and maintainable infrastructure for your application.
Remember to monitor your application’s performance and logs, and make adjustments as necessary to optimize its operation in the production environment. If you’re using SSR, keep an eye on the SSR service to ensure it’s running smoothly and providing the expected performance benefits.
Happy deploying!
References
- GitHub Repository - Source code and examples for this deployment guide