FreeBSD Web Server Stack: NGINX + PHP + PostgreSQL Setup Guide (2026)
This guide walks through building a complete, production-grade web server stack on FreeBSD. By the end, you will have NGINX serving TLS-terminated traffic, PHP-FPM processing dynamic requests, PostgreSQL storing your data, and Redis accelerating everything with caching. Every path, command, and config file is FreeBSD-specific.
Tested on FreeBSD 14.2-RELEASE. All software installed from the official pkg repository.
Table of Contents
- Architecture Overview
- Installing the Stack
- NGINX Configuration
- PHP-FPM Setup
- PostgreSQL Setup
- Redis Caching
- Let's Encrypt SSL
- Performance Tuning
- Security
- WordPress Deployment Example
- Monitoring the Stack
- FAQ
Architecture Overview
The stack follows a standard reverse-proxy pattern:
shellClient (HTTPS:443) | v NGINX (TLS termination, static files, gzip) | v fastcgi_pass 127.0.0.1:9000 PHP-FPM (dynamic content, opcache) | +---> PostgreSQL (persistent data, unix socket) +---> Redis (session store, object cache, tcp 6379)
Request flow: NGINX accepts the incoming HTTPS connection, terminates TLS, and serves static assets directly from disk. For .php requests, NGINX forwards the request to PHP-FPM via FastCGI. PHP-FPM processes the script, querying PostgreSQL for data and Redis for cached objects or sessions, then returns the response to NGINX which delivers it to the client.
Why this stack on FreeBSD:
- ZFS integration for PostgreSQL datasets with tunable recordsize and snapshots.
jailsfor optional service isolation without VM overhead.sysrcandrc.confprovide clean, declarative service management.- Rock-solid network stack with low-latency
kqueueevent handling in NGINX.
For detailed NGINX setup beyond this guide, see our NGINX FreeBSD production setup. For PostgreSQL deep-dives, see PostgreSQL on FreeBSD.
Installing the Stack
Update the package repository and install everything in one pass:
shpkg update && pkg upgrade -y pkg install -y nginx php83 php83-extensions php83-curl php83-gd \ php83-mbstring php83-zip php83-xml php83-pgsql php83-pdo_pgsql \ php83-pecl-redis php83-opcache php83-intl php83-bcmath \ postgresql17-server postgresql17-client redis
Package references: nginx, php83, postgresql17-server, redis.
Enable all services at boot:
shsysrc nginx_enable=YES sysrc php_fpm_enable=YES sysrc postgresql_enable=YES sysrc redis_enable=YES
Verify the installations:
shnginx -v php -v psql --version redis-server --version
NGINX Configuration
All NGINX configuration on FreeBSD lives under /usr/local/etc/nginx/. The main config file is /usr/local/etc/nginx/nginx.conf.
Main Configuration
shvi /usr/local/etc/nginx/nginx.conf
nginxworker_processes auto; worker_rlimit_nofile 65535; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 4096; use kqueue; multi_accept on; } http { include mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; client_max_body_size 64m; # Gzip compression gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 5; gzip_min_length 256; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; # Logging log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent"'; access_log /var/log/nginx/access.log main; # Include server blocks include /usr/local/etc/nginx/conf.d/*.conf; }
Server Block with TLS and FastCGI
Create the conf.d directory and your site config:
shmkdir -p /usr/local/etc/nginx/conf.d vi /usr/local/etc/nginx/conf.d/example.com.conf
nginxserver { listen 80; server_name example.com www.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name example.com www.example.com; root /usr/local/www/example.com; index index.php index.html; # TLS (Let's Encrypt paths, configured later) ssl_certificate /usr/local/etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /usr/local/etc/letsencrypt/live/example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; # Static files location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ { expires 30d; add_header Cache-Control "public, immutable"; access_log off; } # PHP via FastCGI location ~ \.php$ { try_files $uri =404; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; fastcgi_read_timeout 300; fastcgi_buffers 16 16k; fastcgi_buffer_size 32k; } location / { try_files $uri $uri/ /index.php?$args; } # Deny access to hidden files location ~ /\. { deny all; access_log off; log_not_found off; } }
Create the document root and test the config:
shmkdir -p /usr/local/www/example.com chown -R www:www /usr/local/www/example.com nginx -t service nginx start
For the full production NGINX walkthrough including rate limiting and caching, see NGINX FreeBSD production setup.
PHP-FPM Setup
PHP-FPM configuration on FreeBSD lives in /usr/local/etc/php-fpm.d/. The default pool file is www.conf.
Pool Configuration
shcp /usr/local/etc/php.ini-production /usr/local/etc/php.ini vi /usr/local/etc/php-fpm.d/www.conf
Key settings to adjust:
ini[www] user = www group = www listen = 127.0.0.1:9000 listen.allowed_clients = 127.0.0.1 ; Process manager - 'dynamic' for most workloads pm = dynamic pm.max_children = 50 pm.start_servers = 10 pm.min_spare_servers = 5 pm.max_spare_servers = 20 pm.max_requests = 500 ; Status page (restrict access in NGINX) pm.status_path = /fpm-status ping.path = /fpm-ping ; Logging php_admin_value[error_log] = /var/log/php-fpm/www-error.log php_admin_flag[log_errors] = on slowlog = /var/log/php-fpm/www-slow.log request_slowlog_timeout = 5s ; Security php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen php_admin_value[open_basedir] = /usr/local/www/:/tmp/:/var/tmp/
Tuning pm.max_children
Calculate based on available RAM:
sh# Check average PHP-FPM process memory usage ps -auxw | grep php-fpm | awk '{sum += $6; n++} END {print sum/n/1024 " MB average"}'
Formula: pm.max_children = (Available RAM - OS/DB/Redis overhead) / Average PHP process size
For a 4 GB server: roughly (4096 - 1500) / 50 = ~50 children.
OPcache Configuration
Edit /usr/local/etc/php.ini and add or modify:
ini[opcache] opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.revalidate_freq=60 opcache.validate_timestamps=1 opcache.save_comments=1 opcache.fast_shutdown=1 opcache.jit=1255 opcache.jit_buffer_size=128M
Create the log directory and start PHP-FPM:
shmkdir -p /var/log/php-fpm chown www:www /var/log/php-fpm service php-fpm start
Verify PHP-FPM is listening:
shsockstat -l | grep 9000
PostgreSQL Setup
Initialize the Database on ZFS
If you are running ZFS (recommended for PostgreSQL on FreeBSD), create a dedicated dataset:
shzfs create -o mountpoint=/var/db/postgres zpool/postgres zfs set recordsize=16k zpool/postgres zfs set primarycache=metadata zpool/postgres zfs set atime=off zpool/postgres zfs set compression=lz4 zpool/postgres zfs set logbias=throughput zpool/postgres chown postgres:postgres /var/db/postgres
The recordsize=16k matches PostgreSQL's default 8 KB page size with some buffer, and primarycache=metadata avoids double-caching since PostgreSQL manages its own buffer pool via shared_buffers.
Initialize the database cluster:
shsysrc postgresql_data="/var/db/postgres/data17" service postgresql initdb
Authentication (pg_hba.conf)
Edit /var/db/postgres/data17/pg_hba.conf:
shell# TYPE DATABASE USER ADDRESS METHOD local all postgres peer local all all scram-sha-256 host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256
Performance Tuning (postgresql.conf)
Edit /var/db/postgres/data17/postgresql.conf. Settings below are for a server with 8 GB RAM:
shell# Connection settings listen_addresses = 'localhost' port = 5432 max_connections = 100 # Memory shared_buffers = 2GB effective_cache_size = 6GB work_mem = 32MB maintenance_work_mem = 512MB wal_buffers = 64MB # Write-ahead log wal_level = replica max_wal_size = 2GB min_wal_size = 512MB checkpoint_completion_target = 0.9 # Query planner random_page_cost = 1.1 # SSD storage effective_io_concurrency = 200 # SSD storage default_statistics_target = 200 # Logging log_destination = 'stderr' logging_collector = on log_directory = 'log' log_min_duration_statement = 250 log_checkpoints = on log_connections = on log_disconnections = on log_lock_waits = on
Start PostgreSQL and create a database user:
shservice postgresql start su - postgres -c "psql -c \"CREATE USER webapp WITH PASSWORD 'strong_password_here';\"" su - postgres -c "psql -c \"CREATE DATABASE appdb OWNER webapp;\"" su - postgres -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE appdb TO webapp;\""
Test the connection:
shpsql -h 127.0.0.1 -U webapp -d appdb -c "SELECT version();"
For advanced PostgreSQL configuration and backup strategies, see PostgreSQL on FreeBSD.
Redis Caching
Installation and Configuration
Redis configuration on FreeBSD is at /usr/local/etc/redis.conf.
shvi /usr/local/etc/redis.conf
Key settings:
shellbind 127.0.0.1 port 6379 protected-mode yes requirepass your_redis_password_here # Memory management maxmemory 512mb maxmemory-policy allkeys-lru # Persistence (optional, disable for pure cache) save "" # Or keep RDB snapshots: # save 900 1 # save 300 10 # Performance tcp-backlog 511 timeout 300 tcp-keepalive 300 # Logging loglevel notice logfile /var/log/redis/redis.log
shmkdir -p /var/log/redis chown redis:redis /var/log/redis service redis start
Test the connection:
shredis-cli -a your_redis_password_here ping # Should return: PONG
PHP Session Handler via Redis
Edit /usr/local/etc/php.ini:
inisession.save_handler = redis session.save_path = "tcp://127.0.0.1:6379?auth=your_redis_password_here&database=0"
Object Cache Configuration
For application-level caching, configure your PHP application to use Redis. Example connection in PHP:
php$redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('your_redis_password_here'); $redis->select(1); // Use database 1 for object cache // Set a cached value with 300 second TTL $redis->setex('user:42:profile', 300, json_encode($userData)); // Retrieve $cached = $redis->get('user:42:profile'); if ($cached !== false) { $userData = json_decode($cached, true); }
Restart PHP-FPM after changing session settings:
shservice php-fpm restart
For the full Redis setup including Sentinel and replication, see Redis on FreeBSD.
Let's Encrypt SSL
Install Certbot
shpkg install -y py311-certbot py311-certbot-nginx
Obtain a Certificate
Stop NGINX temporarily for the initial certificate (or use the NGINX plugin for zero-downtime):
sh# Option 1: Standalone (requires stopping NGINX) service nginx stop certbot certonly --standalone -d example.com -d www.example.com service nginx start # Option 2: NGINX plugin (no downtime, preferred) certbot --nginx -d example.com -d www.example.com
Certificates are stored at /usr/local/etc/letsencrypt/live/example.com/.
Auto-Renewal
Add a cron job for automatic renewal:
shcrontab -e
shell# Renew Let's Encrypt certificates twice daily 0 3,15 * * * /usr/local/bin/certbot renew --quiet --deploy-hook "service nginx reload"
Alternatively, use a periodic script:
shvi /usr/local/etc/periodic/daily/500.certbot-renew
sh#!/bin/sh /usr/local/bin/certbot renew --quiet --deploy-hook "service nginx reload"
shchmod +x /usr/local/etc/periodic/daily/500.certbot-renew
Test the renewal process:
shcertbot renew --dry-run
For the complete Let's Encrypt walkthrough, see Let's Encrypt on FreeBSD.
Performance Tuning
System-level (sysctl.conf)
Add to /etc/sysctl.conf:
sh# Network stack kern.ipc.somaxconn=4096 kern.ipc.shmmax=2147483648 kern.ipc.shmall=524288 net.inet.tcp.msl=5000 net.inet.tcp.recvspace=65536 net.inet.tcp.sendspace=65536 net.inet.tcp.nolocaltimewait=1 net.inet.tcp.fast_finwait2_recycle=1 net.inet.tcp.cc.algorithm=cubic # File descriptors kern.maxfiles=131072 kern.maxfilesperproc=104856 # Shared memory for PostgreSQL kern.ipc.shmmax=2147483648
Apply immediately:
shsysctl -f /etc/sysctl.conf
Also raise file descriptor limits in /etc/login.conf:
shelldaemon:\ :openfiles-cur=65536:\ :openfiles-max=65536:\ :tc=default:
Rebuild the login database:
shcap_mkdb /etc/login.conf
NGINX Tuning Summary
| Setting | Default | Recommended | Notes |
|---|---|---|---|
| worker_processes | 1 | auto | Matches CPU cores |
| worker_connections | 1024 | 4096 | Per worker |
| keepalive_timeout | 75 | 65 | Reduce for high-traffic |
| client_max_body_size | 1m | 64m | For file uploads |
| gzip_comp_level | 1 | 5 | Balance CPU vs compression |
PHP OPcache Tuning Summary
| Setting | Value | Why |
|---|---|---|
| opcache.memory_consumption | 256 | Enough for large apps |
| opcache.max_accelerated_files | 10000 | Covers most CMS installs |
| opcache.revalidate_freq | 60 | Check for changes every 60s |
| opcache.jit | 1255 | Full JIT for PHP 8.3 |
PostgreSQL Tuning Quick Reference
For an 8 GB RAM server:
| Parameter | Value | Rule of Thumb |
|---|---|---|
| shared_buffers | 2GB | 25% of total RAM |
| effective_cache_size | 6GB | 75% of total RAM |
| work_mem | 32MB | RAM / max_connections / 4 |
| maintenance_work_mem | 512MB | 5-10% of RAM |
| random_page_cost | 1.1 | Use 1.1 for SSD |
| effective_io_concurrency | 200 | Use 200 for SSD |
Security
File Permissions
sh# Web root owned by www, not writable by PHP chown -R www:www /usr/local/www/example.com find /usr/local/www/example.com -type d -exec chmod 755 {} \; find /usr/local/www/example.com -type f -exec chmod 644 {} \; # Writable upload directory (only where needed) mkdir -p /usr/local/www/example.com/uploads chown www:www /usr/local/www/example.com/uploads chmod 750 /usr/local/www/example.com/uploads
NGINX Rate Limiting
Add to the http block in nginx.conf:
nginx# Rate limiting zones limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s; limit_conn_zone $binary_remote_addr zone=connlimit:10m;
Apply in your server block:
nginxlocation / { limit_req zone=general burst=20 nodelay; limit_conn connlimit 50; try_files $uri $uri/ /index.php?$args; } location ~ ^/(wp-login\.php|login|admin) { limit_req zone=login burst=3 nodelay; # ... fastcgi_pass config ... }
PHP Security Settings
In /usr/local/etc/php.ini:
iniexpose_php = Off display_errors = Off display_startup_errors = Off log_errors = On error_log = /var/log/php-fpm/php_errors.log allow_url_fopen = Off allow_url_include = Off max_input_time = 60 max_execution_time = 30 memory_limit = 256M post_max_size = 64M upload_max_filesize = 64M session.cookie_httponly = 1 session.cookie_secure = 1 session.use_strict_mode = 1
PostgreSQL Security
Ensure PostgreSQL only listens on localhost (already set in postgresql.conf):
shelllisten_addresses = 'localhost'
Use scram-sha-256 authentication exclusively (already set in pg_hba.conf above). Avoid trust or md5.
Firewall (IPFW or PF)
Basic PF configuration in /etc/pf.conf:
shellext_if = "vtnet0" set block-policy drop set skip on lo0 # Scrub incoming scrub in all # Default deny block all # Allow SSH, HTTP, HTTPS pass in on $ext_if proto tcp to port { 22, 80, 443 } keep state pass out all keep state
Enable and start PF:
shsysrc pf_enable=YES service pf start
For comprehensive server hardening, see Hardening a FreeBSD server.
WordPress Deployment Example
This section deploys WordPress on the stack we just built. The same general approach works for Nextcloud (see Nextcloud on FreeBSD) or any PHP application.
Create the Database
shsu - postgres -c "psql -c \"CREATE USER wordpress WITH PASSWORD 'wp_db_password_here';\"" su - postgres -c "psql -c \"CREATE DATABASE wordpress OWNER wordpress;\""
Download and Install WordPress
shcd /usr/local/www fetch https://wordpress.org/latest.tar.gz tar xzf latest.tar.gz mv wordpress example.com chown -R www:www example.com rm latest.tar.gz
Configure WordPress for PostgreSQL
WordPress requires a PostgreSQL database driver plugin since it natively uses MySQL. Install the PG4WP plugin:
shcd /usr/local/www/example.com/wp-content mkdir -p mu-plugins fetch -o pg4wp.zip https://github.com/PostgreSQL-For-Wordpress/postgresql-for-wordpress/archive/refs/heads/master.zip unzip pg4wp.zip mv postgresql-for-wordpress-master/pg4wp pg4wp cp pg4wp/db.php ../ rm -rf postgresql-for-wordpress-master pg4wp.zip chown -R www:www /usr/local/www/example.com
Alternatively, use MySQL/MariaDB if you prefer a standard WordPress setup. Install with pkg install -y mariadb1011-server and adjust the configuration accordingly.
WordPress wp-config.php
shcd /usr/local/www/example.com cp wp-config-sample.php wp-config.php vi wp-config.php
Set the database credentials:
phpdefine('DB_NAME', 'wordpress'); define('DB_USER', 'wordpress'); define('DB_PASSWORD', 'wp_db_password_here'); define('DB_HOST', '127.0.0.1'); define('DB_CHARSET', 'utf8mb4'); // Redis object cache define('WP_REDIS_HOST', '127.0.0.1'); define('WP_REDIS_PORT', 6379); define('WP_REDIS_PASSWORD', 'your_redis_password_here'); define('WP_REDIS_DATABASE', 2); // Security define('DISALLOW_FILE_EDIT', true); define('WP_AUTO_UPDATE_CORE', true);
Generate unique salts:
shcurl -s https://api.wordpress.org/secret-key/1.1/salt/
Paste the output into wp-config.php, replacing the placeholder salt values.
NGINX Server Block for WordPress
Update your /usr/local/etc/nginx/conf.d/example.com.conf location block:
nginxlocation / { try_files $uri $uri/ /index.php?$args; } # Deny access to sensitive WordPress files location ~ /\.(htaccess|htpasswd) { deny all; } location = /wp-config.php { deny all; } location ~* /wp-content/uploads/.*\.php$ { deny all; } location ~* /(?:xmlrpc\.php)$ { deny all; }
Reload NGINX:
shnginx -t && service nginx reload
Visit https://example.com to complete the WordPress installation wizard.
Install Redis Object Cache Plugin
After WordPress is running, install the Redis Object Cache plugin via WP-CLI or the admin panel. This plugin uses the WP_REDIS_* constants from wp-config.php and drastically reduces database queries on subsequent page loads.
shpkg install -y php83-pecl-redis service php-fpm restart
Monitoring the Stack
Checking Service Status
sh# All services at once service nginx status service php-fpm status service postgresql status service redis status
Quick Health Check Script
Save as /usr/local/sbin/stack-check.sh:
sh#!/bin/sh echo "=== Stack Health Check ===" # NGINX if service nginx status > /dev/null 2>&1; then echo "[OK] NGINX is running" else echo "[FAIL] NGINX is down" fi # PHP-FPM if service php-fpm status > /dev/null 2>&1; then echo "[OK] PHP-FPM is running" echo " Active processes: $(sockstat -l | grep -c ':9000')" else echo "[FAIL] PHP-FPM is down" fi # PostgreSQL if service postgresql status > /dev/null 2>&1; then echo "[OK] PostgreSQL is running" echo " Active connections: $(su - postgres -c 'psql -t -c "SELECT count(*) FROM pg_stat_activity;"' 2>/dev/null)" else echo "[FAIL] PostgreSQL is down" fi # Redis if redis-cli ping > /dev/null 2>&1; then echo "[OK] Redis is running" echo " Memory used: $(redis-cli info memory | grep used_memory_human | cut -d: -f2)" else echo "[FAIL] Redis is down" fi echo "=== Disk Usage ===" df -h / /var/db/postgres 2>/dev/null echo "=== Load Average ===" uptime
shchmod +x /usr/local/sbin/stack-check.sh
Log Locations
| Service | Log Path |
|---|---|
| NGINX access | /var/log/nginx/access.log |
| NGINX error | /var/log/nginx/error.log |
| PHP-FPM error | /var/log/php-fpm/www-error.log |
| PHP-FPM slow | /var/log/php-fpm/www-slow.log |
| PostgreSQL | /var/db/postgres/data17/log/ |
| Redis | /var/log/redis/redis.log |
| System | /var/log/messages |
Log Rotation
FreeBSD uses newsyslog for log rotation. Add entries to /etc/newsyslog.conf:
shell/var/log/nginx/access.log www:www 644 7 * @T00 JB /var/run/nginx.pid 30 /var/log/nginx/error.log www:www 644 7 * @T00 JB /var/run/nginx.pid 30 /var/log/php-fpm/www-error.log www:www 644 7 * @T00 JB /var/log/redis/redis.log redis:redis 644 7 * @T00 JB
FAQ
How much RAM does this stack need?
A minimum of 2 GB for a light-traffic site. For production with PostgreSQL tuning, 4-8 GB is the practical baseline. The biggest consumers are shared_buffers (PostgreSQL) and pm.max_children (PHP-FPM). On a 2 GB server, set shared_buffers=512MB and pm.max_children=15.
Should I use Unix sockets or TCP for PHP-FPM?
Unix sockets are slightly faster since they avoid TCP overhead. To switch, change NGINX's fastcgi_pass to unix:/var/run/php-fpm.sock and set listen = /var/run/php-fpm.sock in the PHP-FPM pool config along with listen.owner = www and listen.group = www. TCP (127.0.0.1:9000) is used in this guide for clarity and because it simplifies debugging with sockstat.
How do I update packages without breaking the stack?
Use pkg upgrade which respects ABI compatibility. Before upgrading, take a ZFS snapshot:
shzfs snapshot zpool/ROOT/default@before-upgrade zfs snapshot zpool/postgres@before-upgrade pkg upgrade -y service nginx restart service php-fpm restart service postgresql restart service redis restart
If something breaks, roll back: zfs rollback zpool/ROOT/default@before-upgrade.
Can I run this stack in a FreeBSD jail?
Yes, and it is recommended for multi-tenant setups. Create a jail per application or per client. Each jail gets its own NGINX, PHP-FPM, and either its own PostgreSQL instance or connects to a shared PostgreSQL on the host. Redis can be shared across jails by binding to the host's loopback interface and using VNET jail networking. See Hardening a FreeBSD server for jail setup patterns.
Summary
You now have a complete, production-ready web stack on FreeBSD:
- NGINX handles TLS, serves static files, and proxies PHP requests.
- PHP-FPM processes dynamic content with OPcache and JIT enabled.
- PostgreSQL stores persistent data on a tuned ZFS dataset.
- Redis accelerates sessions and object caching.
- Let's Encrypt provides free, auto-renewing TLS certificates.
All managed through sysrc and rc.conf, with logs in predictable locations and a health check script to verify the stack.
For the individual deep-dives referenced throughout this guide: