Running a LAMP server
WebGen is a KVM host and workstation first, but it also carries a complete,
from-source LAMP stack — Apache, PHP-FPM and MariaDB — plus an ACME client for free TLS.
This guide stands up a stock Laravel application at example.com, served over
HTTPS on ports 80 and 443. Swap in your own app: the wiring is identical.
sudo.1 · What you install
| Web server | Apache 2.4.68 (httpd, MPM event) — talks to PHP over mod_proxy_fcgi, no mod_php. |
|---|---|
| PHP | PHP 8.5.8 as php-fpm on 127.0.0.1:9000. OPcache is built in. Config in /etc/php. |
| Database | MariaDB 11.8.8 LTS. Socket /run/mysqld/mysqld.sock, config /etc/my.cnf.d/. |
| TLS | acme.sh 3.1.4 — a pure-shell Let’s Encrypt client (no Python, unlike certbot). |
The web tier and the data tier are separate groups — install both:
sudo wgpkg update
sudo wgpkg install --group server # Apache + PHP-FPM + acme.sh (the web tier)
sudo wgpkg install --group database # your data tier -- see below
The server group is Apache, PHP-FPM and acme.sh. The database
group holds every data service — MariaDB, PostgreSQL and Valkey, each split into a client and a
server package so a box that only needs a client doesn’t pull a whole daemon. For a classic LAMP
app just add MariaDB: sudo wgpkg install mariadb. For image manipulation, queues, or other
PHP extensions add the php-extras group. Then pull the app’s toolchain —
git and Composer are the usual pair (Composer runs on the PHP you just
installed).
2 · The database
The first start initialises the data directory; then create a database and a user for the app.
sudo rc-service mariadb start # first start runs mariadb-install-db
sudo mariadb <<'SQL'
CREATE DATABASE example CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'example'@'localhost' IDENTIFIED BY 'change-this-password';
GRANT ALL PRIVILEGES ON example.* TO 'example'@'localhost';
FLUSH PRIVILEGES;
SQL
MariaDB ships tuned for a 1-core / 1 GB box (the tiny tier). To scale up,
edit /etc/my.cnf.d/webgen.cnf — it carries commented tiny / small
/ med / large blocks; the knobs that matter most are
innodb_buffer_pool_size (the working-set cache) and max_connections. It
binds to 127.0.0.1 only, so the database is never exposed to the network by default.
3 · PHP-FPM
PHP-FPM already ships a working pool listening on 127.0.0.1:9000 as the
http user, and a production php.ini. The simplest setup is to let the app
be owned by that same http user, so no pool edit is needed:
sudo rc-service php-fpm start
/etc/php/php-fpm.d/<app>.conf — do not edit the stock
www.conf. A wgpkg upgrade of PHP overwrites package-shipped configs,
which would silently revert your change and break file writes.4 · Apache → PHP
Load the proxy modules and point a virtual host at the app’s public/ directory,
handing .php requests to php-fpm. Add to /etc/httpd/httpd.conf:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
Include /etc/httpd/extra/example.conf
Then /etc/httpd/extra/example.conf:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /srv/www/example-app/public
<Directory /srv/www/example-app/public>
AllowOverride All
Require all granted
</Directory>
<FilesMatch \.php$>
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
</VirtualHost>
5 · Deploy the Laravel app
Create a stock Laravel app (or clone yours) under /srv/www, install dependencies,
set it up, and hand ownership to the http user so PHP can write storage/.
sudo install -d -o $USER -g http /srv/www
cd /srv/www
composer create-project laravel/laravel example-app
cd example-app
cp .env.example .env
# point .env at the database from step 2:
# DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_DATABASE=example
# DB_USERNAME=example DB_PASSWORD=change-this-password
# APP_URL=https://example.com
php artisan key:generate
php artisan migrate --force
php artisan storage:link
php artisan config:cache && php artisan route:cache
sudo chown -R http:http /srv/www/example-app
sudo rc-service apache2 restart
composer.lock caps PHP below 8.5.8, composer install refuses; run
composer update once to re-resolve against the installed PHP, then commit the new lock.6 · Open the firewall
Inbound is denied by default except SSH. Open 80 and 443. In the desktop, Settings →
Network → Firewall lists the live rules in a table — click Add allow rule for
tcp/80 and tcp/443, then Apply. Headless, edit
/etc/nftables.conf:
tcp dport { 80, 443 } accept
# then reload:
sudo nft -f /etc/nftables.conf
sudo rc-service firewall restart
6.1 · The same rules in the Settings app
On the desktop the firewall is a panel, not a file. Settings → Network → Firewall
lists the rules in a table — and it reads the live nftables ruleset, so the
two ports you just opened (by hand, or by a recipe) appear here too, not just a hardcoded default.
Use Add allow rule and the trash icon to change them; Apply writes
/etc/nftables.conf and reloads. For this web server it looks like:
Inbound is denied by default; add the ports to open. Reflects the live ruleset and is written to /etc/nftables.conf.
| Direction | Source | Protocol | Port | Action |
|---|---|---|---|---|
| Inbound | Any | TCP | 22 | Allow |
| Inbound | Any | TCP | 80 | Allow |
| Inbound | Any | TCP | 443 | Allow |
| Inbound | Any | Any | Any | Drop |
SSH (22) stays open so a remote box can’t lock you out; 80 and 443 are the two you added for the web server; everything else falls through to the default Drop.
7 · HTTPS with Let’s Encrypt
With Apache already answering on port 80, issue and install a certificate over the webroot. The
--reloadcmd keeps it renewing automatically.
sudo acme.sh --set-default-ca --server letsencrypt
sudo acme.sh --issue -d example.com -w /srv/www/example-app/public --keylength ec-256
sudo acme.sh --install-cert -d example.com --ecc \
--key-file /etc/httpd/ssl/example.key \
--fullchain-file /etc/httpd/ssl/example.crt \
--reloadcmd "rc-service apache2 reload"
Add the TLS <VirtualHost *:443> (same DocumentRoot and
SetHandler as port 80, plus SSLEngine on and the
SSLCertificateFile/SSLCertificateKeyFile paths above), and redirect 80→443.
8 · Start at boot
sudo rc-update add mariadb default
sudo rc-update add php-fpm default
sudo rc-update add apache2 default
For Laravel’s queue and scheduler, run php artisan queue:work under a small
OpenRC service and add php artisan schedule:run to /etc/cron.d/ (the
per-minute driver Laravel expects).
9 · Redeploy
Day to day, pull and refresh caches:
cd /srv/www/example-app
git pull
composer install --no-dev
php artisan migrate --force
php artisan config:cache && php artisan route:cache
sudo rc-service php-fpm reload