Skip to main content
ClaudeWave
Skill1.4k repo starsupdated 27d ago

php-deploy

The php-deploy skill automates building and deploying PHP applications by detecting frameworks (Laravel, Symfony, WordPress, or generic PHP), managing dependencies via Composer, configuring appropriate document roots, and orchestrating startup tasks like database migrations and optimization. Use this skill when deploying any PHP project or when composer.json or index.php files are detected in the project root.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/nixopus/nixopus /tmp/php-deploy && cp -r /tmp/php-deploy/api/skills/php-deploy ~/.claude/skills/php-deploy
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# PHP Deployment

## Detection

Project is PHP if any of these exist:

- `composer.json` at the build context root
- `index.php` at the root

## Versions

PHP 8.2+ only.

1. `composer.json` → `require.php` (e.g. `">=8.2"`)
2. `.php-version` or `mise.toml` / `.tool-versions`
3. Defaults to **8.4**

## Package Manager

Composer. Detect `composer.json` and `composer.lock`.

| Has lock file | Command |
|---|---|
| yes | `composer install --no-dev --optimize-autoloader` |
| no | `composer install --no-dev --optimize-autoloader` |

## Document Root

Laravel and Symfony use `public/`. Generic PHP uses the project root.

## PHP Extensions

Detected from `composer.json` → `require` section with `ext-*` entries.

## Framework Detection

| Signal | Framework |
|---|---|
| `artisan` | Laravel |
| `symfony.lock` or `config/` structure | Symfony |
| `wp-config.php` | WordPress |
| `index.php` + routing | Generic PHP |

### Laravel-Specific

When `artisan` is present:

- Document root: `public/`
- Migrations run by default during startup. Skip by setting `SKIP_MIGRATIONS=true`.
- Storage symlinks, optimization
- Build-time artisan caches: config, routes, views, events
- Storage directory must be writable

## Startup Process

1. Run migrations (Laravel; skip if `SKIP_MIGRATIONS=true`)
2. Create storage symlinks (Laravel: `php artisan storage:link`)
3. Optimize (Laravel: config/route/view cache)
4. Start PHP server (FrankenPHP, PHP-FPM, or `php -S`)

Override by providing custom `start-container.sh` in project root.

## Node.js Integration

If `package.json` detected alongside PHP (e.g. Laravel + Vite):

- Install Node.js
- Run `npm install` or equivalent
- Execute build scripts from `package.json`
- Prune dev dependencies in final image

## Install Stage Optimization

Copy `composer.json` + `composer.lock` first for layer caching.

## Caching

```dockerfile
RUN --mount=type=cache,target=/root/.composer/cache \
    composer install --no-dev --optimize-autoloader
```

## Base Images

| Use case | Image |
|---|---|
| FrankenPHP | `dunglas/frankenphp:latest` or `dunglas/frankenphp:php8.4` |
| PHP-FPM | `php:8.4-fpm-alpine` |
| CLI / built-in server | `php:8.4-cli-alpine` |

## Dockerfile Patterns

### Laravel with FrankenPHP

```dockerfile
FROM composer:2 AS deps
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader

FROM php:8.4-cli-alpine AS build
WORKDIR /app
COPY --from=deps /app/vendor ./vendor
COPY . .
RUN php artisan config:cache && php artisan route:cache && php artisan view:cache

FROM dunglas/frankenphp:php8.4
WORKDIR /app
COPY --from=build /app .
EXPOSE 8080
CMD ["frankenphp", "run", "--config", "/app/Caddyfile"]
```

### Generic PHP + Composer

```dockerfile
FROM composer:2 AS deps
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader

FROM php:8.4-fpm-alpine
WORKDIR /app
COPY --from=deps /app/vendor ./vendor
COPY . .
EXPOSE 9000
CMD ["php-fpm"]
```

## Gotchas

- Laravel `storage/` and `bootstrap/cache/` must be writable — `chown` these directories in the Dockerfile for non-root users
- FrankenPHP defaults to port 8080, not 80 — ensure EXPOSE and proxy config match
- Composer `post-autoload-dump` scripts may fail during Docker build if the app isn't fully configured — use `--no-scripts` during install, then run `composer dump-autoload --optimize` after copying source
- PHP OPcache should be enabled in production (`opcache.enable=1`, `opcache.validate_timestamps=0`) for significant performance gains
- Extensions listed in `require` as `ext-*` must be installed in the Docker image — they are not bundled with base PHP images
api-catalogSkill

Reference for all Nixopus API operations callable via nixopus_api(method, path, body)

caddyfile-generationSkill

Generate Caddyfile configurations for static sites and reverse proxies — SPA fallback routing, cache headers, compression, redirects, and error pages. Use when deploying a static site that needs custom Caddy configuration, or when the user needs SPA routing, caching, or redirect rules.

compose-setupSkill

Generate docker-compose.yml for multi-service setups including databases, caches, and service dependencies. Use when the app needs a database, cache, message broker, or has multiple independently deployable services.

container-resource-tuningSkill

Size container memory and CPU limits, diagnose OOM kills and CPU throttling, and recommend resource adjustments by ecosystem. Use when containers are being OOM-killed, running slowly, or when setting initial resource limits for a deployment.

cpp-deploySkill

Build and deploy C/C++ applications — CMake, Meson, Ninja, and Dockerfile patterns. Use when deploying a C or C++ project, or when CMakeLists.txt or meson.build is detected.

database-migrationSkill

Run database migrations safely during deployment — framework-specific commands, pre-deploy vs post-deploy timing, health gates, and rollback strategies. Use when the app has a database migration system and needs migrations run during deployment.

deno-deploySkill

Build and deploy Deno applications — version detection, dependency caching, and Dockerfile patterns. Use when deploying a Deno project, or when deno.json or deno.jsonc is detected.

deploy-delegationSkill

Sub-agent routing table — which agent handles diagnostics, machine health, infrastructure, GitHub, billing, and notifications. Load when the current task is not a direct deployment.