---
title: "How to deploy a PHP app in 2026"
description: "Deploy a PHP app with one command: pethost deploy writes the Dockerfile for Laravel, Symfony or plain PHP pages and serves it over HTTPS, for €9.99 a month."
---

[Blog](https://pethost.dev/blog/) · Deploy guides

# How to deploy a PHP app in 2026: Laravel, Symfony or plain PHP pages with one command

By the Pethost team · 24 October 2026 · Updated 28 October 2026 · 11 min read

You have a PHP app that runs on your laptop: a Laravel project, a Symfony one, or a folder of `.php` pages. You want it online with HTTPS, without setting up a server. On Pethost that is one command, `pethost deploy`, run in the app's folder: it writes the Dockerfile, builds the app on your Pethost machine and prints its address. A project fresh from `laravel new` was built and started in 1 minute 29 seconds, and a folder of two pages in 12 seconds.

**In short**

- **One command:** `pethost deploy` in the folder with `composer.json`, or `index.php` for plain pages. No config file to write.
- **Laravel and Symfony** run on FrankenPHP with PHP 8.4. pethost runs `composer install`, builds the Vite assets, and starts the app in production mode.
- **Plain PHP pages** run on Apache, with your `.htaccess` files and `mod_rewrite`.
- **Laravel's SQLite database** is kept in a volume and migrated at each start, so a new deploy keeps the data.
- **The price:** €9.99 a month for 2 vCPU, 3 GB and 30 GB, for every project you have. There is no free tier.

## What you need to deploy a PHP app in 2026

Three things: the app, the `pethost` command and a Pethost account.

**The app** is a folder on your computer: here a project made by `laravel new`, a Symfony skeleton with one page, and two pages of plain PHP. Docker on your computer is not needed: the image is built on your Pethost machine.

**The command** is one program, installed by one line. Every command it has is in the [CLI's reference](https://pethost.dev/docs/cli/).

```
curl -fsSL https://pethost.dev/install.sh | sh      # macOS, Linux
irm https://pethost.dev/install.ps1 | iex           # Windows, in PowerShell
```

**The account** needs a plan. If you are not signed in, `pethost deploy` opens your browser and signs you in. If you have no plan yet, it shows you where to choose one, and waits.

## Deploy a Laravel app

The app is the one Laravel's installer leaves: `laravel new example-app`, with no starter kit, SQLite as the database, Pest, and the installer's `npm install` and build. Go to its folder and run `pethost deploy`. This is the whole screen:

```
$ cd example-app
$ pethost deploy
Name it [example-app]:      it will live at https://example-app.sam.pethost.app
✓ Packed 10.4k files, 51 MB   (left out node_modules · took .env from this folder)
✓ Uploaded straight to your machine
✗ /compose.yaml: the project directory has no compose.yaml at its root: add one
✓ Laravel project detected, wrote Dockerfile and .dockerignore.
~ The database starts empty on the machine and is migrated at each start: pethost run -- php artisan db:seed --force fills it from the project's seeders.
✓ Packed 10.4k files, 51 MB   (left out node_modules · took .env from this folder)
✓ Uploaded straight to your machine
✓ Built and started in 1 min 29 s
  · wrote compose.yaml for the Dockerfile: the service app, reading .env, port 80, a named volume at /app/storage/app
✓ app listens on 80 → https://example-app.sam.pethost.app
  It answers 200.

https://example-app.sam.pethost.app

Wrote .pethost (commit it). Next:   pethost logs -f   ·   pethost open
```

1. **It asks one thing** The project's name, the first word of its address. Enter takes the folder's name.
2. **The machine finds nothing to run** The line with the cross is its answer: a project runs from a Dockerfile or a Compose file, and the folder has neither yet.
3. **pethost writes the Dockerfile** `composer.json` requires `laravel/framework`, so it writes Laravel's and uploads the folder again.
4. **The machine builds and starts it** Then pethost asks the address, and prints the answer: 200, Laravel's welcome page.

Your `.env`, `APP_KEY` included, became the project's own on the machine. `.pethost` says which project this folder is: commit it with the Dockerfile, and the next deploy asks nothing.

### The Dockerfile that pethost writes for Laravel

These are the lines that matter of the file written into the folder. Its 54 lines say in comments why each step is there:

```
# check=skip=JSONArgsRecommended
# Written by pethost deploy for this Laravel project: composer.json requires
# laravel/framework, package.json builds the assets with "vite build", npm installs it
# (package-lock.json), its SQLite database is kept in storage/app, with the files the
# site is given, it runs in production mode, set over the folder's .env.
# It is yours now: change it as you like. pethost does not write it again.

FROM dunglas/frankenphp:1-php8.4
…
COPY . .

RUN composer install
…
RUN npm run build

ENV DB_DATABASE=/app/storage/app/database.sqlite
# The machine keeps this directory across deploys.
VOLUME /app/storage/app
EXPOSE 80
…
CMD export APP_ENV=production APP_DEBUG=false LOG_CHANNEL=stderr DB_DATABASE=/app/storage/app/database.sqlite && \
    php artisan migrate --force && \
    exec frankenphp run --config /etc/frankenphp/Caddyfile
```

- **The server** is FrankenPHP, built on Caddy, with PHP 8.4. The app is told it runs behind HTTPS, so the URLs Laravel writes start with `https://`. Extensions that `composer.json` requires as `ext-…` are installed.
- **Production mode** is set at the start, over your laptop's `.env`, and logs go to the container's output, where `pethost logs` reads them.
- **The SQLite file** lives in `storage/app`, which the machine keeps in a volume across deploys, and migrations run before the server starts.

## Run artisan commands on the machine

`pethost run` runs one command in the app's container. Here Laravel's own migrations, after three deploys:

```
$ pethost run -- php artisan migrate:status
example-app (.pethost)

  Migration name .............................................. Batch / Status
  0001_01_01_000000_create_users_table ............................... [1] Ran
  0001_01_01_000001_create_cache_table ............................... [1] Ran
  0001_01_01_000002_create_jobs_table ................................ [1] Ran
```

All three are in batch 1: they ran at the first start, and the database came through the two deploys after it. `pethost run -- php artisan db:seed --force` fills it from your seeders, as the line with the tilde said, and `pethost shell` opens a shell for `php artisan tinker`.

A Laravel project whose `.env` names MySQL or Postgres gets no Dockerfile, since the database must run beside it. pethost says so:

```
✗ /compose.yaml: the project directory has no compose.yaml at its root: add one
  .env names a database other than SQLite (DB_CONNECTION=pgsql), and the machine runs none beside a Dockerfile: the project needs a compose.yaml with the site and its database.
```

A `compose.yaml` with the app and its database runs as written. Or make a database in one click, at no extra cost, and link it to the app: a MariaDB for an app made for MySQL, or a Postgres ([Postgres at a flat price](https://pethost.dev/blog/european-hosting-postgres-flat-price/)).

## Deploy a Symfony app

The app is Symfony's skeleton, `composer create-project symfony/skeleton my-project` (the same as `symfony new my-project`), with the controller of Symfony's “Create your First Page”: `src/Controller/LuckyController.php`, whose route `/lucky/number` answers a random number. The same command deploys it:

```
$ cd my-project
$ pethost deploy
Name it [my-project]:        it will live at https://my-project.sam.pethost.app
✓ Packed 1.7k files, 7.9 MB   (took .env from this folder)
✓ Uploaded straight to your machine
✗ /compose.yaml: the project directory has no compose.yaml at its root: add one
✓ Symfony project detected, wrote Dockerfile and .dockerignore.
✓ Packed 1.7k files, 7.9 MB   (took .env from this folder)
✓ Uploaded straight to your machine
✓ Built and started in 57 s
  · wrote compose.yaml for the Dockerfile: the service app, reading .env, port 80
✓ app listens on 80 → https://my-project.sam.pethost.app
  It answers 404.

https://my-project.sam.pethost.app

Wrote .pethost (commit it). Next:   pethost logs -f   ·   pethost open
```

The answer is 404 because the app has no route at `/`, and in production Symfony shows no welcome page. Ask the route that exists:

```
$ curl https://my-project.sam.pethost.app/lucky/number
<html><body>Lucky number: 27</body></html>
```

Symfony's Dockerfile is Laravel's without Node and the database. `APP_ENV=prod` is set for `composer install`, which warms the cache, and at the start, over the `.env` Symfony commits with `APP_ENV=dev`. AssetMapper's assets are compiled in the build. A project with Doctrine entities in `src/Entity` gets no Dockerfile: it needs a `compose.yaml` with its database.

## Deploy plain PHP pages

No framework, no Composer: a folder with `index.php`, which shows a form, and `hello.php`, which reads `$_POST['name']` and says hello.

```
$ cd my-site
$ pethost deploy
Name it [my-site]:              it will live at https://my-site.sam.pethost.app
✓ Packed 2 files, 604 B
✓ Uploaded straight to your machine
✗ /compose.yaml: the project directory has no compose.yaml at its root: add one
✓ PHP site detected, wrote Dockerfile.
~ Every file of the folder is public at its address, but for the Dockerfile and names that begin with a dot.
✓ Packed 3 files, 1 KB
✓ Uploaded straight to your machine
✓ Built and started in 12 s
  · wrote compose.yaml for the Dockerfile: the service app, reading .env, port 80
✓ app listens on 80 → https://my-site.sam.pethost.app
  It answers 200.

https://my-site.sam.pethost.app

Wrote .pethost (commit it). Next:   pethost logs -f   ·   pethost open
```

```
$ curl -d name=Sam https://my-site.sam.pethost.app/hello.php
…
  <p>Hello, Sam!</p>
```

The Dockerfile is PHP's official `php:8.4-apache` image serving the folder, with PHP's production settings. `.htaccess` files work, with `mod_rewrite` on. Read the line with the tilde: every file of the folder is public, so a secret goes in the project's variables. Pages that open a database with `mysqli` or `PDO` need a `compose.yaml` with it, and pethost says so.

## Change the code and deploy again

Add a route to `routes/web.php` and run the same command:

```
Route::get('/hello', function () {
    return 'Hello from Laravel!';
});
```

```
$ pethost deploy
example-app (.pethost)
✓ Packed 10.4k files · uploaded · built and started in 48 s
  · kept the project's .env in place of the version's own: after the first deploy the project's is kept
  · wrote compose.yaml for the Dockerfile: the service app, reading .env, port 80, a named volume at /app/storage/app
  · kept the project's x-pethost
  It answers 200.
https://example-app.sam.pethost.app
To send this folder's .env:  pethost env push
```

Note the second line: after the first deploy, the machine keeps the project's `.env`, not your laptop's. `pethost env set` changes a variable and deploys at once:

```
$ pethost env set APP_URL=https://example-app.sam.pethost.app
example-app (.pethost)
✓ /.env has APP_URL now. Deployed in 48 s.
```

A bare name asks for a secret without showing it: `pethost env set MAIL_PASSWORD`. `pethost github sam/example-app` deploys every push from then on, and `pethost rollback` puts the version before back. An AI agent can do all of this through Pethost's MCP server: [how an agent deploys and looks after a project](https://pethost.dev/blog/hosting-for-ai-coding-agents/).

## Use your own domain for the PHP app

Every name under your account's domain works at once, with HTTPS. A domain you own takes one command and one DNS record:

```
pethost domain add www.example.com
```

It prints the record: a CNAME to your machine's name. The certificate comes once the name resolves, and renews itself.

## What you get for the price

Pethost is €9.99 a month for everything you host, on 2 vCPU, 3 GB of memory and 30 GB of disk. That is room for the Laravel app, its queue worker, a database and your next project, with [no fee per project](https://pethost.dev/blog/unlimited-projects-flat-monthly-fee/) and nothing metered. The machine is always on, so a visitor [never waits for a cold start](https://pethost.dev/blog/always-on-hosting-no-cold-starts/).

- **€9.99** a month for all your projects, nothing metered
- **1 min 29 s** to build and start a new Laravel app, the first time
- **12 s** for a folder of PHP pages

What is already done for you: HTTPS with certificates that renew themselves, deploys from GitHub, nightly backups kept for 14 days, SSH into any container, and every request counted, with no script in your pages. The plans are on the [pricing](https://pethost.dev/#pricing) part of the first page.

**Every project, labeled.** Seven projects on one Starter machine: the apps with their addresses and requests of the last day, the databases with the apps that use them.

![The Pethost panel's first page: the machine's CPU, memory and disk, and its projects as cards.](https://pethost.dev/shots/projects.webp)

### Pethost is the best pick for

- **PHP developers with a Laravel or Symfony app** who want it online without running a server
- **People moving off shared hosting** with a folder of PHP pages and a few more projects to come
- **People whose agent deploys for them**: Claude Code or Codex puts the app online and reads its logs
- **Early startups** who want a fixed monthly cost while the product is small

### Look elsewhere if

- Your application needs several regions or autoscaling

## Questions

### How do I deploy a PHP app without writing a Dockerfile?

Run `pethost deploy` in the app's folder. For a Laravel or Symfony project, or a folder with `index.php`, it writes the Dockerfile and deploys it. The file stays in your folder for you to change.

### Which PHP version does Pethost run?

The Dockerfiles pethost writes run PHP 8.4: on FrankenPHP for Laravel and Symfony, on Apache for plain pages. The version is in the Dockerfile's `FROM` line, which is yours.

### Does the Laravel SQLite database survive a redeploy?

Yes. The file is in `storage/app`, which the machine keeps in a volume, and each start runs `php artisan migrate --force`. Two deploys later, the migrations still showed batch 1.

### Can I deploy a Laravel app with MySQL or Postgres?

Yes, with a `compose.yaml` that runs the app beside its database: pethost writes no Dockerfile for it, and says so. Or link the app to a database made in one click, at no extra cost: a MariaDB for an app made for MySQL, or a Postgres.

### What does it cost to host a PHP app on Pethost?

€9.99 a month for Starter, with 2 vCPU, 3 GB and 30 GB and no fee per project: your other apps and databases run there too. There is no free tier. Prices are without VAT.

The screens are deploys on a test machine of ours, with pethost 0.2.4: a project made by Laravel's installer 5.32.0 (Laravel 13.38.0), Symfony 8.1.9's skeleton, and two pages of plain PHP, all on PHP 8.4.27. The Laravel deploy came first; the Symfony one used the FrankenPHP image it had pulled. The account in them is the example one, `sam`.

1. [Laravel: installation](https://laravel.com/docs/13.x/installation)
2. [Laravel: deployment](https://laravel.com/docs/13.x/deployment)
3. [Symfony: installing and setting up the framework](https://symfony.com/doc/current/setup.html)
4. [Symfony: create your first page](https://symfony.com/doc/current/page_creation.html)
5. [FrankenPHP: documentation](https://frankenphp.dev/docs/)
6. [PHP: the official Docker image](https://hub.docker.com/_/php)
7. [pethost, the command line of Pethost](https://pethost.dev/docs/cli/)

## Put your projects online today

Deploy apps, bots and databases from your agent, GitHub or the browser, as many as fit, at one flat price. Nothing metered, nothing billed on top.

[Host all your projects for €9.99/mo](https://console.pethost.dev/)

## Keep reading

- 10 October 2026 [How to deploy a Gin app in 2026: one command, HTTPS and a Dockerfile you keep](https://pethost.dev/blog/deploy-gin-app/) Deploy a Go Gin app with one command: pethost deploy writes the Dockerfile, builds the program and serves it over HTTPS, for €9.99 a month.
- 10 October 2026 [How to deploy a Go Fiber app in 2026: one command, HTTPS and a Dockerfile you keep](https://pethost.dev/blog/deploy-fiber-app/) Deploy a Go Fiber app with one command: pethost deploy writes the Dockerfile, builds it in 45 seconds and serves it over HTTPS, for €9.99 a month.
- 10 October 2026 [How to deploy a Nuxt app in 2026: one command, a Node server and HTTPS](https://pethost.dev/blog/deploy-nuxt-app/) Deploy a Nuxt 4 app with one command: pethost deploy writes the Dockerfile, runs nuxt build and starts the Node server over HTTPS, for €9.99 a month.
- 10 October 2026 [How to deploy a React Router app in 2026: the template's Dockerfile, one command and HTTPS](https://pethost.dev/blog/deploy-react-router-app/) Deploy a React Router app with server rendering: pethost deploy builds the template's own Dockerfile and serves it over HTTPS in 11 seconds, for €9.99 a month.

[All articles](https://pethost.dev/blog/) · [About Pethost](https://pethost.dev/about/) · [Pricing](https://pethost.dev/#pricing)

Pethost · Stephan Gomer · NIP 1133096755

Pethost

- [Templates](https://pethost.dev/templates/)
- [About](https://pethost.dev/about/)
- [Docs](https://pethost.dev/docs/)
- [Blog](https://pethost.dev/blog/)
- [API](https://pethost.dev/docs/api/)
- [CLI](https://pethost.dev/docs/cli/)
- [Plugin](https://github.com/pethost-dev/plugin)
- [Terms](https://pethost.dev/terms/)
- [Privacy](https://pethost.dev/privacy/)
- [Refunds](https://pethost.dev/refunds/)
- [support@pethost.dev](mailto:support@pethost.dev)

Databases

- [Postgres](https://pethost.dev/postgres/)

Comparisons

- [Coolify vs Dokploy vs CapRover vs Dokku](https://pethost.dev/blog/coolify-vs-dokploy-vs-caprover-vs-dokku/)
- [Coolify Cloud vs Dokploy Cloud](https://pethost.dev/blog/coolify-cloud-vs-dokploy-cloud/)
- [Railway vs Render vs Fly.io pricing](https://pethost.dev/blog/railway-vs-render-vs-fly-io-pricing/)
- [Managed Docker Compose hosting](https://pethost.dev/blog/managed-docker-compose-hosting/)

Alternatives

- [Railway alternatives](https://pethost.dev/blog/railway-alternatives/)
- [Heroku alternatives](https://pethost.dev/blog/heroku-alternatives/)
- [Dokploy alternatives](https://pethost.dev/blog/dokploy-alternatives/)
- [Coolify alternatives](https://pethost.dev/blog/coolify-alternatives/)
- [Render alternatives](https://pethost.dev/blog/render-alternatives/)
- [Sliplane alternatives](https://pethost.dev/blog/sliplane-alternatives/)
