# dispelled.ca PHP package
This archive is the complete PHP source tree for the site. It requires PHP 8.2+
and the JSON, SimpleXML/XML, mbstring, and OpenSSL extensions. No Node.js,
Composer, database, cron job, or build step is required.
## Source layout
The archive root is the package root:
```text
/var/www/dispelled-ca/
├── package.json
├── router.php
├── cache/
│ └── .gitkeep
├── public/ # web document root
│ ├── index.php
│ ├── includes/
│ ├── categories/
│ ├── css/
│ ├── images/
│ └── .htaccess
└── scripts/
```
`public/` is the document root for Apache, Nginx, Caddy, and PHP-FPM. Keep the
package root and `cache/` outside that document root. The included
`public/.htaccess` is packaged from the real source tree; it does not depend on
or hard-code a `RewriteBase`, so it also works below a URL prefix.
## Built-in development server
Run this from the package root, not from `public/`:
```sh
php -S 127.0.0.1:3001 router.php
```
For a subdirectory deployment, set `BASE_PATH` to the URL prefix with a leading
slash and no trailing slash, for example `BASE_PATH=/dispelled`. The router
matches that prefix as a complete path segment, so `/app` does not match
`/apple`.
## Web servers
Point the server's document root at `/var/www/dispelled-ca/public`. Configure
PHP-FPM to execute the `.php` files under that directory and allow PHP to write
`/var/www/dispelled-ca/cache`. Nginx and Caddy should deny requests for
`/includes/` and other private files; Apache can use the included
`public/.htaccess` plus the usual virtual-host access rules.
For a subdirectory, map `/dispelled` to the `public/` directory and set
`BASE_PATH=/dispelled`. Do not put the package root itself on the public web.
## Shared hosting
Keep the same separation when the host provides a document-root directory:
upload the contents of `public/` to that document root and keep `cache/` in the
location resolved by `public/includes/config.php`. If the host requires a
different layout, edit that source file's `CACHE_DIR` definition explicitly.
Do not upload runtime cache JSON files. If the host only offers one
directory, ask it for a private writable path for cache rather than exposing
the package root.
The PHP account must be able to create and replace JSON files in `cache/`.
Enable HTTPS, `allow_url_fopen`, outbound DNS/HTTPS, and the listed PHP
extensions. The cache is disposable and is not part of the archive except for
the empty `.gitkeep` marker.
## Apache example
```apache
DocumentRoot /var/www/dispelled-ca/public
<Directory /var/www/dispelled-ca/public>
Options -Indexes
AllowOverride All
Require all granted
</Directory>
<Directory /var/www/dispelled-ca/cache>
Require all denied
</Directory>
```
## Nginx with PHP-FPM
```nginx
root /var/www/dispelled-ca/public;
index index.php;
location / { try_files $uri $uri/ =404; }
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ^~ /includes/ { deny all; }
```
## Caddy with PHP-FPM
```caddy
root * /var/www/dispelled-ca/public
@private path /includes/*
respond @private 404
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
```
Check the PHP-FPM socket and filesystem permissions for the operating system.
Do not expose the built-in development server directly to the Internet.