FreeBSD.software
Home/Guides/How to Install and Configure Apache on FreeBSD
tutorial·2026-04-09·10 min read

How to Install and Configure Apache on FreeBSD

Complete guide to installing and configuring Apache HTTP Server on FreeBSD: httpd.conf, virtual hosts, mod_ssl with Let's Encrypt, MPM selection, and essential modules.

How to Install and Configure Apache on FreeBSD

Apache HTTP Server remains the most widely deployed web server in the world. On FreeBSD, it integrates cleanly with the system's package infrastructure, rc.d service management, and filesystem layout. This guide covers installation, core configuration, virtual hosts, SSL/TLS with Let's Encrypt, MPM selection, essential modules, and performance tuning for production deployments.

Prerequisites

  • FreeBSD 14.0 or later
  • Root access
  • A domain name pointing to your server (for SSL configuration)

Step 1: Install Apache

Apache is available as a binary package. The current stable branch is 2.4:

sh
pkg install apache24

This installs the Apache HTTP server, utilities (apachectl, htpasswd, ab), and default configuration files under /usr/local/etc/apache24/.

Enable Apache at Boot

sh
sysrc apache24_enable="YES"

Start Apache

sh
service apache24 start

Verify it is running:

sh
service apache24 status curl -I http://localhost

You should see a "200 OK" response with "Apache" in the Server header. The default document root is /usr/local/www/apache24/data/.

Step 2: Understand the File Layout

Apache on FreeBSD follows the standard /usr/local prefix:

| Path | Purpose |

|------|---------|

| /usr/local/etc/apache24/httpd.conf | Main configuration file |

| /usr/local/etc/apache24/extra/ | Additional configuration files (vhosts, SSL, etc.) |

| /usr/local/etc/apache24/modules.d/ | Module-specific configurations |

| /usr/local/etc/apache24/Includes/ | Drop-in include directory |

| /usr/local/www/apache24/data/ | Default document root |

| /usr/local/www/apache24/cgi-bin/ | CGI scripts directory |

| /var/log/httpd-access.log | Access log (default) |

| /var/log/httpd-error.log | Error log (default) |

| /usr/local/libexec/apache24/ | Compiled modules (.so files) |

| /var/run/httpd.pid | PID file |

Step 3: Configure httpd.conf

The main configuration file is /usr/local/etc/apache24/httpd.conf. The default file is heavily commented and functional out of the box. Key directives to review and modify:

Server Identity

sh
# Edit the main config vi /usr/local/etc/apache24/httpd.conf

Set the server name to avoid the "Could not reliably determine the server's fully qualified domain name" warning:

sh
ServerName www.example.com:80

Listen Directives

By default, Apache listens on port 80 on all interfaces:

sh
Listen 80

To bind to a specific IP:

sh
Listen 192.168.1.10:80

User and Group

Apache runs worker processes as the www user and group on FreeBSD:

sh
User www Group www

Do not change this unless you have a specific reason. The www user has minimal privileges by design.

Directory Permissions

The default document root configuration:

sh
<Directory "/usr/local/www/apache24/data"> Options Indexes FollowSymLinks AllowOverride None Require all granted </Directory>

For production, disable directory indexing and enable .htaccess if needed:

sh
<Directory "/usr/local/www/apache24/data"> Options FollowSymLinks AllowOverride All Require all granted </Directory>

Enable Essential Modules

Uncomment these lines in httpd.conf to enable commonly needed modules:

sh
LoadModule rewrite_module libexec/apache24/mod_rewrite.so LoadModule ssl_module libexec/apache24/mod_ssl.so LoadModule socache_shmcb_module libexec/apache24/mod_socache_shmcb.so LoadModule headers_module libexec/apache24/mod_headers.so LoadModule expires_module libexec/apache24/mod_expires.so LoadModule deflate_module libexec/apache24/mod_deflate.so LoadModule proxy_module libexec/apache24/mod_proxy.so LoadModule proxy_fcgi_module libexec/apache24/mod_proxy_fcgi.so

After editing, test the configuration:

sh
apachectl configtest

If the output says "Syntax OK", restart Apache:

sh
service apache24 restart

Step 4: Set Up Virtual Hosts

Virtual hosts allow one Apache instance to serve multiple websites. Enable the virtual hosts configuration file by uncommenting this line in httpd.conf:

sh
Include etc/apache24/extra/httpd-vhosts.conf

Create a Virtual Host

Edit /usr/local/etc/apache24/extra/httpd-vhosts.conf:

sh
<VirtualHost *:80> ServerName example.com ServerAlias www.example.com DocumentRoot "/usr/local/www/example.com" ErrorLog "/var/log/example.com-error.log" CustomLog "/var/log/example.com-access.log" combined <Directory "/usr/local/www/example.com"> Options FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>

Create the document root and set permissions:

sh
mkdir -p /usr/local/www/example.com chown -R www:www /usr/local/www/example.com

Create a test page:

sh
echo "<h1>example.com works</h1>" > /usr/local/www/example.com/index.html chown www:www /usr/local/www/example.com/index.html

Multiple Virtual Hosts

Add additional blocks for each site. Apache matches by ServerName and ServerAlias:

sh
<VirtualHost *:80> ServerName site1.example.com DocumentRoot "/usr/local/www/site1" <Directory "/usr/local/www/site1"> AllowOverride All Require all granted </Directory> </VirtualHost> <VirtualHost *:80> ServerName site2.example.com DocumentRoot "/usr/local/www/site2" <Directory "/usr/local/www/site2"> AllowOverride All Require all granted </Directory> </VirtualHost>

Test and reload:

sh
apachectl configtest service apache24 graceful

The graceful restart allows active connections to complete before the new configuration takes effect.

Step 5: Configure SSL/TLS with Let's Encrypt

Install Certbot

sh
pkg install py311-certbot py311-certbot-apache

Obtain a Certificate

Certbot can automatically configure Apache SSL:

sh
certbot --apache -d example.com -d www.example.com

Certbot will:

  1. Verify domain ownership via HTTP challenge
  2. Obtain the certificate from Let's Encrypt
  3. Create or modify the SSL virtual host configuration
  4. Set up automatic redirect from HTTP to HTTPS

Manual SSL Configuration

If you prefer manual configuration or use certificates from another CA, enable the SSL configuration in httpd.conf:

sh
Include etc/apache24/extra/httpd-ssl.conf

Edit /usr/local/etc/apache24/extra/httpd-ssl.conf or create a dedicated vhost:

sh
<VirtualHost *:443> ServerName example.com DocumentRoot "/usr/local/www/example.com" SSLEngine on SSLCertificateFile "/usr/local/etc/letsencrypt/live/example.com/fullchain.pem" SSLCertificateKeyFile "/usr/local/etc/letsencrypt/live/example.com/privkey.pem" # Modern TLS configuration SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384 SSLHonorCipherOrder off # HSTS header Header always set Strict-Transport-Security "max-age=63072000" <Directory "/usr/local/www/example.com"> AllowOverride All Require all granted </Directory> </VirtualHost>

HTTP to HTTPS Redirect

Add a redirect in the HTTP virtual host:

sh
<VirtualHost *:80> ServerName example.com ServerAlias www.example.com Redirect permanent "/" "https://example.com/" </VirtualHost>

Automatic Certificate Renewal

Certbot sets up a cron job or periodic task for renewal. Verify:

sh
certbot renew --dry-run

Add to /etc/periodic.conf for FreeBSD periodic integration:

sh
# Add to /etc/crontab or use crontab -e 0 3 * * * /usr/local/bin/certbot renew --quiet --deploy-hook "service apache24 graceful"

Listen on port 443 -- make sure this line exists in httpd.conf:

sh
Listen 443

Step 6: Choose an MPM

MPM (Multi-Processing Module) determines how Apache handles concurrent connections. FreeBSD supports three MPMs:

prefork

One process per connection. Compatible with non-thread-safe modules (e.g., mod_php). Higher memory usage.

sh
LoadModule mpm_prefork_module libexec/apache24/mod_mpm_prefork.so

Configuration in httpd.conf:

sh
<IfModule mpm_prefork_module> StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxRequestWorkers 250 MaxConnectionsPerChild 0 </IfModule>

worker

Hybrid multi-process/multi-threaded. Lower memory footprint. Not compatible with mod_php (use PHP-FPM instead).

sh
LoadModule mpm_worker_module libexec/apache24/mod_mpm_worker.so
sh
<IfModule mpm_worker_module> StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 0 </IfModule>

event

Improved worker MPM with better handling of keep-alive connections. Recommended for modern deployments with PHP-FPM.

sh
LoadModule mpm_event_module libexec/apache24/mod_mpm_event.so
sh
<IfModule mpm_event_module> StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 0 </IfModule>

Only one MPM can be loaded at a time. Comment out the others. For new deployments serving PHP through PHP-FPM, use the event MPM.

Step 7: Set Up PHP with PHP-FPM

Rather than mod_php (which requires prefork MPM), use PHP-FPM with the event or worker MPM for better performance.

Install PHP-FPM

sh
pkg install php83 php83-extensions

Enable PHP-FPM

sh
sysrc php_fpm_enable="YES" service php-fpm start

Configure Apache to Use PHP-FPM

Add to your virtual host or global configuration:

sh
<FilesMatch "\.php$"> SetHandler "proxy:fcgi://127.0.0.1:9000" </FilesMatch>

Or using a Unix socket (lower overhead):

sh
<FilesMatch "\.php$"> SetHandler "proxy:unix:/var/run/php-fpm.sock|fcgi://localhost" </FilesMatch>

Ensure mod_proxy and mod_proxy_fcgi are loaded (see Step 3).

Create a test PHP file:

sh
echo "<?php phpinfo(); ?>" > /usr/local/www/example.com/info.php chown www:www /usr/local/www/example.com/info.php

Test and restart:

sh
apachectl configtest service apache24 restart

Visit https://example.com/info.php to verify PHP is working. Delete this file after testing.

Step 8: Essential Modules

mod_rewrite

URL rewriting is critical for most web applications (WordPress, Laravel, etc.):

sh
LoadModule rewrite_module libexec/apache24/mod_rewrite.so

Example .htaccess for a PHP application:

sh
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L]

mod_deflate

Enable gzip compression for text-based content:

sh
<IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/xml AddOutputFilterByType DEFLATE text/css text/javascript AddOutputFilterByType DEFLATE application/javascript application/json AddOutputFilterByType DEFLATE application/xml application/xhtml+xml </IfModule>

mod_expires

Set caching headers for static assets:

sh
<IfModule mod_expires.c> ExpiresActive On ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" </IfModule>

mod_headers

Add security headers:

sh
<IfModule mod_headers.c> Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Header always set X-XSS-Protection "1; mode=block" Header always set Referrer-Policy "strict-origin-when-cross-origin" </IfModule>

Step 9: Security Hardening

Hide Server Version

sh
ServerTokens Prod ServerSignature Off

Disable Directory Listing

sh
<Directory "/usr/local/www"> Options -Indexes </Directory>

Restrict Access to Sensitive Files

sh
<FilesMatch "^\.ht"> Require all denied </FilesMatch> <FilesMatch "\.(env|ini|log|bak)$"> Require all denied </FilesMatch>

Limit Request Size

sh
LimitRequestBody 10485760

This limits upload size to 10 MB. Adjust based on your application requirements.

Disable Unnecessary Modules

Review loaded modules and disable any you do not use. Each loaded module increases memory usage and attack surface:

sh
# List loaded modules apachectl -M

Step 10: Log Management

Log Format

The default "combined" log format provides useful information:

sh
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

Log Rotation

FreeBSD's newsyslog handles log rotation. Add to /etc/newsyslog.conf:

sh
/var/log/httpd-access.log www:www 640 7 * @T00 JC /var/run/httpd.pid 30 /var/log/httpd-error.log www:www 640 7 * @T00 JC /var/run/httpd.pid 30

This rotates logs daily, keeps 7 copies, compresses them, and sends a graceful restart signal to Apache.

Separate Logs Per Virtual Host

Each virtual host should have its own logs:

sh
<VirtualHost *:443> ServerName example.com ErrorLog "/var/log/example.com-error.log" CustomLog "/var/log/example.com-access.log" combined </VirtualHost>

Performance Tuning

KeepAlive Settings

sh
KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5

Keep KeepAliveTimeout low (2-5 seconds) to prevent idle connections from consuming worker slots.

File Descriptor Limits

For high-traffic servers, increase file descriptor limits in /etc/login.conf:

sh
# After editing login.conf, rebuild the database cap_mkdb /etc/login.conf

Also set in /etc/sysctl.conf:

sh
kern.maxfiles=65536 kern.maxfilesperproc=32768

Enable sendfile

FreeBSD's sendfile system call is more efficient for serving static files:

sh
EnableSendfile On

This is usually enabled by default on FreeBSD.

Frequently Asked Questions

What is the difference between service apache24 restart and service apache24 graceful?

restart stops and starts Apache, dropping all active connections. graceful signals Apache to finish serving active requests before reloading configuration. Always use graceful on production servers when possible.

Can I run Apache and NGINX on the same server?

Yes, but not on the same port. A common pattern is NGINX on port 80/443 as a reverse proxy, with Apache on port 8080 as the backend. This combines NGINX's static file performance with Apache's module ecosystem.

How do I check which MPM is loaded?

sh
apachectl -V | grep MPM

Why does Apache fail to start after enabling SSL?

Ensure both mod_ssl and mod_socache_shmcb are loaded. Check that your certificate and key files exist and are readable by the www user. Test with apachectl configtest for specific errors.

How do I password-protect a directory?

Use htpasswd to create a password file and configure the directory:

sh
htpasswd -c /usr/local/etc/apache24/.htpasswd admin
sh
<Directory "/usr/local/www/example.com/admin"> AuthType Basic AuthName "Restricted Area" AuthUserFile /usr/local/etc/apache24/.htpasswd Require valid-user </Directory>

How do I enable HTTP/2?

Load the HTTP/2 module and enable it in SSL virtual hosts:

sh
LoadModule http2_module libexec/apache24/mod_http2.so
sh
<VirtualHost *:443> Protocols h2 http/1.1 # ... rest of SSL config </VirtualHost>

HTTP/2 requires the event or worker MPM. It does not work with prefork.

How do I serve multiple sites with different PHP versions?

Run multiple PHP-FPM pools on different ports or sockets. Configure each virtual host to proxy to the appropriate PHP-FPM instance:

sh
# Site using PHP 8.3 <FilesMatch "\.php$"> SetHandler "proxy:unix:/var/run/php83-fpm.sock|fcgi://localhost" </FilesMatch>

Can I use Apache as a reverse proxy?

Yes. Enable mod_proxy and mod_proxy_http:

sh
<VirtualHost *:443> ServerName app.example.com ProxyPreserveHost On ProxyPass "/" "http://127.0.0.1:3000/" ProxyPassReverse "/" "http://127.0.0.1:3000/" </VirtualHost>

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.