Setting up a WordPress Subdomain¶
This guide sets up a fresh WordPress site on its own subdomain (example: blek.franzvoid.is → /var/www/blek.franzvoid.is/), served by Apache with PHP-FPM and MariaDB, secured with Let's Encrypt. It leaves WordPress at its browser install wizard so you can create the admin account yourself.
For the general subdomain/vhost mechanics, see Setup Subdomains. This page is the WordPress-specific end-to-end.
0. Prerequisites¶
- Apache already installed and running (see Setup Apache).
- DNS: franzvoid.is has a wildcard
*.franzvoid.isrecord (at Dynu) pointing at the server, so any new*.franzvoid.issubdomain resolves automatically — no A record to add. For a different domain, create an A record first and confirm it resolves:dig +short A <subdomain>. sudoaccess.
Throughout, replace <subdomain> with your site (e.g. blek.franzvoid.is) and <docroot> with /var/www/<subdomain>.
1. Install PHP-FPM, extensions, and MariaDB¶
This server runs the Apache event MPM, so PHP must run through PHP-FPM — mod_php is not an option.
sudo apt update
sudo apt install -y \
php8.2-fpm php8.2-mysql php8.2-gd php8.2-curl php8.2-xml \
php8.2-mbstring php8.2-zip php8.2-intl php8.2-bcmath php8.2-imagick \
mariadb-server
Confirm both services are up:
2. Wire PHP-FPM into Apache¶
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.2-fpm # routes *.php to /run/php/php8.2-fpm.sock for all vhosts
sudo systemctl reload apache2
3. Create the database¶
MariaDB root uses unix_socket auth, so sudo mariadb logs in without a password. Pick a strong password (openssl rand -base64 24 is handy) and substitute it below:
sudo mariadb <<'SQL'
CREATE DATABASE blek_wp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'blek_wp'@'localhost' IDENTIFIED BY 'CHANGE-ME-STRONG-PASSWORD';
GRANT ALL PRIVILEGES ON blek_wp.* TO 'blek_wp'@'localhost';
FLUSH PRIVILEGES;
SQL
Keep the DB name, user, and password — they go into wp-config.php next.
4. Download WordPress¶
cd /tmp
curl -fsSL -o wp.tar.gz https://downloads.wordpress.org/release/wordpress-7.0.1.tar.gz
tar xzf wp.tar.gz
grep "wp_version =" wordpress/wp-includes/version.php # sanity-check the version
sudo mkdir -p /var/www/<subdomain>
sudo cp -a wordpress/. /var/www/<subdomain>/
For the latest version instead of a pinned one, use
https://wordpress.org/latest.tar.gz.
5. Create wp-config.php¶
Generate fresh security salts and write the config. Run this from a working dir, then copy the result into place:
DBPASS='CHANGE-ME-STRONG-PASSWORD'
SALTS="$(curl -fsSL https://api.wordpress.org/secret-key/1.1/salt/)"
cat > /tmp/wp-config.php <<EOF
<?php
// ** Database settings ** //
define( 'DB_NAME', 'blek_wp' );
define( 'DB_USER', 'blek_wp' );
define( 'DB_PASSWORD', '${DBPASS}' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
// ** Authentication unique keys and salts ** //
${SALTS}
\$table_prefix = 'wp_';
define( 'WP_DEBUG', false );
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';
EOF
php -l /tmp/wp-config.php # syntax check
sudo cp /tmp/wp-config.php /var/www/<subdomain>/wp-config.php
6. Set ownership and permissions¶
Apache and PHP-FPM run as www-data, so the whole tree must be owned by it:
sudo chown -R www-data:www-data /var/www/<subdomain>
sudo find /var/www/<subdomain> -type d -exec chmod 755 {} \;
sudo find /var/www/<subdomain> -type f -exec chmod 644 {} \;
sudo chmod 640 /var/www/<subdomain>/wp-config.php # keep DB creds tighter
7. Create the Apache virtual host¶
Create only the :80 vhost — certbot generates the HTTPS vhost and redirect in the next step. AllowOverride All lets WordPress's .htaccess (permalinks) work.
/etc/apache2/sites-available/<subdomain>.conf:
<VirtualHost *:80>
ServerName <subdomain>
DocumentRoot /var/www/<subdomain>
DirectoryIndex index.php index.html
<Directory /var/www/<subdomain>>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/<subdomain>_error.log
CustomLog ${APACHE_LOG_DIR}/<subdomain>_access.log combined
</VirtualHost>
Enable it and reload:
Sanity-check over HTTP before TLS — this should redirect to /wp-admin/install.php:
8. Enable HTTPS with Certbot¶
Certbot writes <subdomain>-le-ssl.conf (SSL vhost) and adds the HTTP→HTTPS redirect:
Verify:
curl -s -o /dev/null -w "%{http_code}\n" http://<subdomain>/ # expect 301
curl -s -L https://<subdomain>/ | grep -o '<title>[^<]*</title>' # expect "WordPress › Installation"
9. Finish the install in the browser¶
Because wp-config.php already contains the DB settings, WordPress skips the database step. Open https://<subdomain>/ and the wizard goes straight to picking the site title, admin username, and password. Set those and log in — the site is then yours to populate.
Notes¶
- Harden the REST API user endpoints afterwards: see Disable wp-json user enumeration.
- The Let's Encrypt cert auto-renews via certbot's scheduled task; nothing else to do.