Skip to content

Deploy guide · PHP / Laravel

Deploy PHP / Laravel in minutes.

Connect the repository, Railpack builds it, the service gets a domain with TLS. Databases from templates, usage drawn per minute from a prepaid balance, everything on EU nodes.

terminal
$ npm i -g skiffly && skiffly login
$ cd my-laravel-app && skiffly init
$ skiffly deploy --template postgres
$ skiffly variables set 'DB_URL=${{Postgres.DATABASE_URL}}' APP_ENV=production
$ skiffly up

What Railpack detects

Railpack inspects the repository and picks the build for PHP / Laravel; most projects need no configuration. A Dockerfile in the repository always wins.

  • composer.json with laravel/framework
  • artisan
  • public/index.php
Builder
Railpack (default)
Start command
php artisan migrate --force && php artisan serve --host=0.0.0.0 --port=$PORT

Derived by Railpack; override it in Settings → Deploy → Start command.

Port and $PORT

Skiffly injects PORT into every service and routes the public domain to it. Set the port in the service settings when your app listens on a fixed one; the default is 8080 for PHP / Laravel, 8080 when nothing is set.

Listen on $PORT
php artisan serve --host=0.0.0.0 --port=$PORT
PORT
8080
SKIFFLY_PUBLIC_DOMAIN
<service>.skiffly.cloud

From a terminal

Install the CLI, link the directory, deploy. skiffly up builds the pushed HEAD of the current branch and streams the build logs; skiffly domain gives the service a *.skiffly.cloud address.

Or describe it once

.skiffly/skiffly.ts declares the service, its databases and the references between them. skiffly config plan shows the diff, skiffly config apply makes it so. The API mirrors railway/iac.

Config as code
.skiffly/skiffly.ts
// .skiffly/skiffly.ts
import { defineSkiffly, generate, github, postgres, project, redis, service } from "@skiffly/config";

export default defineSkiffly(() => {
  const db = postgres("db");
  const cache = redis("cache");

  const web = service("web", {
    source: github("acme/web"),
    start: "php artisan migrate --force && php artisan serve --host=0.0.0.0 --port=$PORT",
    port: 8080,
    healthcheck: "/",
    env: {
      DATABASE_URL: db.env.DATABASE_URL,
      REDIS_URL: cache.env.REDIS_URL,
      APP_ENV: "production",
      APP_KEY: generate("hex32"),
    },
  });

  return project("web", { resources: [web, db, cache] });
});

PHP / Laravel on Skiffly: common questions

How do I set environment variables for PHP / Laravel?
In the service's Variables tab, with skiffly variables set KEY=value, or in .skiffly/skiffly.ts. Reference other services with ${{Postgres.DATABASE_URL}} and environment-wide values with ${{shared.NAME}}. Secrets are encrypted at rest.
Can I change the build or start command?
Yes. Settings → Build → Build command overrides Railpack's build step; Settings → Deploy → Start command replaces the start command. A monorepo sets a root directory so the build runs inside it.
How do I add Postgres or Redis?
Deploy the template into the same environment. It arrives with a volume, generated credentials and a connection URL you reference from the PHP / Laravel service. Connect from your laptop with skiffly connect postgres.
Do I get preview environments per pull request?
Turn on PR previews on the project: every pull request gets its own copy of the environment on its own domain, removed when the PR is merged or closed. Forks are ignored.
What does a small PHP / Laravel app cost?
A 512 MB / 0.25 vCPU service runs at about $7.75 a month, drawn per minute from your balance. Add Postgres with 512 MB / 0.25 vCPU and a 10 GB volume for about $9 more. The free tier runs one 512 MB service with App Sleeping at no cost.
Can the PHP / Laravel service sleep when idle?
Turn on App Sleeping: after about 10 minutes without a request it scales to zero and wakes on the next one (2–10 s). CPU and memory are not billed while asleep; the volume is.

Deploy your PHP / Laravel app today

Free tier without a card. Hobby from $5 with $5 of usage included.