# Deployment

A few practical rules for shipping changes to the production server. Keep specific addresses, access details and credentials out of public documentation and out of the repository (in `.env` and your private notes).

## Web architecture

A typical production setup: `nginx` in front serves all static files (css/js/img) directly, while PHP is proxied to Apache/PHP-FPM (which reads `.htaccess`). The key rules below follow from this.

## After editing templates (.tpl)

Compiled templates are cached in `storage/cache/tpl/`. After changing a `.tpl` in production, **clear the cache**:

```
rm -f storage/cache/tpl/*
```

Locally the cache invalidates by file modification time automatically; the admin has **Settings → Performance → Clear cache**. It's also useful to reload PHP-FPM to reset opcache.

## After editing static files (.css/.js)

`nginx` caches static files for a long time (e.g. 30 days). After changing a file, **bump the version** in the include:

```html
<link rel="stylesheet" href="/templates/<theme>/assets/landing.css?v=6">
```

`?v=6` → `?v=7`. Otherwise returning visitors get the old version from cache. Cache headers are configured in the `nginx` config, not in `.htaccess` (for static files `.htaccess` doesn't apply — `nginx` serves them).

## File permissions

Site files usually belong to a dedicated system user. After copying new files, restore the owner (`chown`) and, if needed, permissions so the PHP process can read/write (`storage/`, `public/assets/plugins/`).

## Database

- Local — PostgreSQL, production — MySQL: write cross-database code (see [Migrations](/docs/code/migrations)).
- Before `DELETE`/`ALTER` in production — **back up** (`mysqldump` of the relevant table) and use narrow `WHERE` conditions.
- MySQL implicitly commits DDL — keep this in mind when relying on rollback.

## Pitfalls (don't step on these)

| Symptom | Cause | Fix |
|---------|-------|-----|
| Visitors see old CSS/JS | nginx static cache | bump `?v=` |
| Old look after editing a .tpl | compiled-template cache | clear `storage/cache/tpl/*` |
| Apache 500 | `<Directory>`/`php_flag` in `.htaccess` with PHP-FPM | remove these directives |
| External script doesn't work | CSP blocks the CDN | host the asset locally |
| Cache headers not applied | set in `.htaccess` | set in the `nginx` config |

## Post-deploy check

A simple self-test of the home page (with a User-Agent so bot filters don't kick in):

```
curl -s -o /dev/null -w '%{http_code}' -A "Mozilla/5.0" https://<domain>/
```

`200` means all good. Check key sections too after large changes.
