Web Server ConfigurationSetting up a web server on MidnightBSD allows you to host websites, web applications, and APIs.
MidnightBSD supports both nginx and Apache HTTP Server through mports,
giving you flexibility to choose the web server that best fits your needs. Both servers are production-ready
and widely used in enterprise environments.
This guide covers installation, configuration, security hardening, and performance tuning for both nginx and Apache on MidnightBSD, including setting up HTTPS with Let's Encrypt certificates and configuring virtual hosts for multiple websites.
Use Nginx if you need:
Use Apache if you need:
Common approach: Many deployments use both - nginx as a reverse proxy in front of Apache for static content and SSL termination, with Apache handling dynamic content. This provides the performance benefits of nginx with the flexibility of Apache.
Nginx is available through mports and can be installed with:
# mport install nginx
Enable nginx to start at boot:
# sysrc nginx_enable=YES # service nginx start
Verify nginx is running:
# service nginx status # ps aux | grep nginx
Test nginx installation: After starting nginx, visit http://localhost in your
browser. You should see the default nginx welcome page.
Nginx files and directories:
/usr/local/etc/nginx/ - Main configuration directory/usr/local/etc/nginx/nginx.conf - Primary configuration file/usr/local/etc/nginx/conf.d/ - Additional configuration files/usr/local/www/nginx/ - Default web root directory/usr/local/www/nginx/dist/ - Default static files/var/log/nginx/ - Log files (access.log, error.log)/usr/local/sbin/nginx - Nginx binaryThe main nginx configuration file is /usr/local/etc/nginx/nginx.conf. It includes
other configuration files from the conf.d/ directory.
Main configuration structure:
# Main context - affects all server blocks
user www;
worker_processes auto;
# Error log location
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
# Events context
events {
worker_connections 1024;
}
# HTTP context - contains server blocks
http {
include /usr/local/etc/nginx/mime.types;
default_type application/octet-stream;
# Log format definitions
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Server configuration
include /usr/local/etc/nginx/conf.d/*.conf;
}
Testing configuration: After making changes to nginx configuration:
# Test configuration syntax nginx -t # If test passes, reload nginx service nginx reload
Basic server block:
server {
listen 80;
server_name localhost;
# Root directory
root /usr/local/www/nginx;
index index.html index.htm;
# Location blocks
location / {
try_files $uri $uri/ =404;
}
# Error pages
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx;
}
}
Common configuration directives:
| Directive | Description | Example |
|---|---|---|
listen |
IP address and port to listen on | listen 80; or listen 192.168.1.100:80; |
server_name |
Server names (domain names) for this block | server_name example.com www.example.com; |
root |
Root directory for requests | root /usr/local/www/example; |
index |
Default files to serve | index index.html index.php; |
location |
Defines how to handle requests to specific paths | location /images/ { ... } |
try_files |
Try files in order until one is found | try_files $uri $uri/ =404; |
Virtual hosts allow you to host multiple websites on a single server. Create separate configuration
files for each site in /usr/local/etc/nginx/conf.d/.
Basic virtual host setup:
# Create configuration file for example.com
vi /usr/local/etc/nginx/conf.d/example.com.conf
server {
listen 80;
server_name example.com www.example.com;
root /usr/local/www/example.com;
index index.html index.php;
# Custom error pages
error_page 404 /404.html;
location / {
try_files $uri $uri/ =404;
}
# PHP-FPM configuration (if using PHP)
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
# Reload nginx to apply changes
nginx -t && service nginx reload
IP-based virtual hosts:
# Multiple IPs on same server
server {
listen 192.168.1.100:80;
server_name site1.com;
root /usr/local/www/site1;
}
server {
listen 192.168.1.101:80;
server_name site2.com;
root /usr/local/www/site2;
}
Port-based virtual hosts:
# Same IP, different ports
server {
listen 80;
server_name example.com;
root /usr/local/www/example-http;
}
server {
listen 8080;
server_name example.com;
root /usr/local/www/example-admin;
}
Default server block:
# Default server - catches all requests not matching other server_name directives
server {
listen 80 default_server;
server_name _;
root /usr/local/www/default;
# Return 444 to drop connection for undefined server names
# return 444;
}
Setting up HTTPS with free certificates from Let's Encrypt using Certbot.
Install Certbot and nginx plugin:
# mport install certbot certbot-nginx
Obtain certificate:
# Stop nginx temporarily service nginx stop # Obtain certificate (webroot method) certbot certonly --webroot -w /usr/local/www/example.com -d example.com -d www.example.com # Or standalone method (nginx must be stopped) certbot certonly --standalone -d example.com -d www.example.com # Start nginx again service nginx start
Automatic certificate renewal:
# Test renewal certbot renew --dry-run # Add to cron for automatic renewal (runs twice daily) 0 */12 * * * /usr/local/bin/certbot renew --quiet --post-hook "service nginx reload"
Configure nginx for HTTPS:
server {
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;
# SSL certificate configuration
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 and ciphers
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Strong SSL settings
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# Root directory
root /usr/local/www/example.com;
index index.html index.php;
location / {
try_files $uri $uri/ =404;
}
}
Security headers:
# Add to your HTTPS server block add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always;
HTTP/2 support: nginx supports HTTP/2 automatically when using SSL. Just add
http2 to the listen directive: listen 443 ssl http2;
Worker processes:
# In nginx.conf
events {
worker_connections 2048; # Maximum connections per worker
}
http {
# Auto-detect number of CPU cores
worker_processes auto;
}
Buffer and timeout settings:
http {
# Buffer sizes
client_body_buffer_size 16k;
client_header_buffer_size 1k;
client_max_body_size 10m;
large_client_header_buffers 4 16k;
# Timeouts
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 75;
send_timeout 12;
}
Gzip compression:
http {
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
}
File serving optimization:
http {
# Enable sendfile for static files
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Cache static files
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
# For static file locations
location /static/ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
Configure nginx as a reverse proxy to forward requests to backend servers (Apache, Node.js, etc.).
Reverse proxy to application server:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
Reverse proxy to Apache:
upstream apache_backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name example.com;
# Static files served by nginx
location / {
root /usr/local/www/example.com;
try_files $uri @apache;
}
# Dynamic content proxied to Apache
location @apache {
proxy_pass http://apache_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Static files cache
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
Load balancing across multiple backend servers:
upstream backend_servers {
server 192.168.1.101:8000;
server 192.168.1.102:8000;
server 192.168.1.103:8000;
# Load balancing algorithm
least_conn; # Send request to server with least active connections
# Other options: round_robin (default), ip_hash, least_time
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend_servers;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Create a new website:
# 1. Create directory structure
mkdir -p /usr/local/www/mysite.com/{public_html,logs,cgi-bin}
# 2. Create basic index.html
cat > /usr/local/www/mysite.com/public_html/index.html << 'EOF'
Welcome to mysite.com
mysite.com
EOF
# 3. Create nginx configuration
cat > /usr/local/etc/nginx/conf.d/mysite.com.conf << 'EOF'
server {
listen 80;
server_name mysite.com www.mysite.com;
root /usr/local/www/mysite.com/public_html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
EOF
# 4. Test and reload
nginx -t && service nginx reload
Redirect HTTP to HTTPS:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Redirect www to non-www:
server {
listen 80;
server_name www.example.com;
return 301 http://example.com$request_uri;
}
Serve static files efficiently:
location /static/ {
root /usr/local/www;
expires 30d;
add_header Cache-Control "public, no-transform";
# Disable access logging for static files
access_log off;
}
Disable directory listing:
location / {
autoindex off;
}
Password protect a directory:
# 1. Create password file
printf "admin:" | htpasswd -c /usr/local/etc/nginx/.htpasswd admin
# You'll be prompted for the password
# 2. Configure location
location /admin/ {
auth_basic "Admin Area";
auth_basic_user_file /usr/local/etc/nginx/.htpasswd;
}
Enable HTTP/2: Add http2 to your listen directive:
listen 443 ssl http2;
Apache HTTP Server (httpd) is available through mports:
# mport install apache24
Enable Apache to start at boot:
# sysrc apache24_enable=YES # service apache24 start
Verify Apache is running:
# service apache24 status # ps aux | grep httpd
Test Apache installation: Visit http://localhost in your browser.
You should see the Apache default page.
Apache files and directories:
/usr/local/etc/apache24/ - Main configuration directory/usr/local/etc/apache24/httpd.conf - Primary configuration file/usr/local/etc/apache24/extra/ - Additional configuration files/usr/local/etc/apache24/Includes/ - Included configuration files/usr/local/www/apache24/ - Default document root/usr/local/www/apache24/cgi-bin/ - Default CGI directory/usr/local/www/apache24/data/ - Default htdocs directory/var/log/apache24/ - Log files/usr/local/sbin/apachectl - Apache control scriptThe main Apache configuration file is /usr/local/etc/apache24/httpd.conf.
It includes several other configuration files.
Key configuration sections:
# Global Environment ServerRoot "/usr/local" # Main server configuration Listen 80 ServerAdmin admin@example.com ServerName localhost:80 # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory DocumentRoot "/usr/local/www/apache24/data" # Directory configurationOptions Indexes FollowSymLinks AllowOverride None Require all granted # Include additional configuration files Include /usr/local/etc/apache24/extra/*.conf
Testing configuration:
# Test configuration syntax apachectl -t # If test passes, restart Apache service apache24 restart
Configuration file hierarchy:
httpd.conf - Main configurationextra/httpd-ssl.conf - SSL configurationextra/httpd-vhosts.conf - Virtual hostsextra/httpd-default.conf - Default serverextra/httpd-autoindex.conf - Directory indexingextra/httpd-cgi.conf - CGI configurationCommon Apache directives:
| Directive | Description | Example |
|---|---|---|
Listen |
IP address and port to listen on | Listen 80 or Listen 192.168.1.100:80 |
ServerName |
Server name and port | ServerName example.com:80 |
DocumentRoot |
Root directory for documents | DocumentRoot /usr/local/www/example |
DirectoryIndex |
Default files to serve | DirectoryIndex index.html index.php |
ErrorLog |
Error log location | ErrorLog /var/log/apache24/error.log |
CustomLog |
Access log location and format | CustomLog /var/log/apache24/access.log common |
Apache virtual hosts can be configured in /usr/local/etc/apache24/extra/httpd-vhosts.conf
or in individual files in the Includes/ directory.
Name-based virtual hosts:
# In /usr/local/etc/apache24/extra/httpd-vhosts.confServerAdmin admin@example.com ServerName example.com ServerAlias www.example.com DocumentRoot /usr/local/www/example.com Options Indexes FollowSymLinks AllowOverride All Require all granted ErrorLog /var/log/apache24/example.com-error.log CustomLog /var/log/apache24/example.com-access.log commonServerAdmin admin@anothersite.com ServerName anothersite.com ServerAlias www.anothersite.com DocumentRoot /usr/local/www/anothersite.com Options Indexes FollowSymLinks AllowOverride All Require all granted ErrorLog /var/log/apache24/anothersite.com-error.log CustomLog /var/log/apache24/anothersite.com-access.log common
IP-based virtual hosts:
ServerName site1.com DocumentRoot /usr/local/www/site1 ServerName site2.com DocumentRoot /usr/local/www/site2
Port-based virtual hosts:
# Main site on port 80ServerName example.com DocumentRoot /usr/local/www/example-http # Admin site on port 8080ServerName example.com DocumentRoot /usr/local/www/example-admin
Default virtual host:
# First virtual host defined becomes the defaultServerName default.example.com DocumentRoot /usr/local/www/default # Or redirect all undefined hosts Redirect permanent / http://example.com/
Setting up HTTPS with Apache using Let's Encrypt certificates.
Enable SSL module:
# Check if SSL module is loaded (look for mod_ssl.so) httpd -M | grep ssl # If not enabled, uncomment or add to httpd.conf LoadModule ssl_module modules/mod_ssl.so # Include SSL configuration Include /usr/local/etc/apache24/extra/httpd-ssl.conf
Obtain Let's Encrypt certificate:
# Install certbot mport install certbot certbot-apache # Stop Apache temporarily service apache24 stop # Obtain certificate certbot certonly --standalone -d example.com -d www.example.com # Start Apache again service apache24 start
Configure HTTPS virtual host:
ServerName example.com ServerAlias www.example.com DocumentRoot /usr/local/www/example.com # SSL Configuration SSLEngine on SSLCertificateFile /usr/local/etc/letsencrypt/live/example.com/cert.pem SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/example.com/privkey.pem SSLCertificateChainFile /usr/local/etc/letsencrypt/live/example.com/chain.pem # SSL protocols and ciphers SSLProtocol -all +TLSv1.2 +TLSv1.3 SSLCipherSuite HIGH:!aNULL:!MD5:!3DES SSLHonorCipherOrder on # Security headers Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" Header always set X-Content-Type-Options "nosniff" Header always set X-Frame-Options "SAMEORIGIN" Options Indexes FollowSymLinks AllowOverride All Require all granted ErrorLog /var/log/apache24/example.com-ssl-error.log CustomLog /var/log/apache24/example.com-ssl-access.log common
Redirect HTTP to HTTPS:
ServerName example.com ServerAlias www.example.com Redirect permanent / https://example.com/
Automatic certificate renewal:
# Add to cron 0 */12 * * * /usr/local/bin/certbot renew --quiet --post-hook "service apache24 restart"
MPM (Multi-Processing Module) settings:
# Check current MPM httpd -V | grep -i mpm # For prefork MPM (traditional, one process per connection)StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxRequestWorkers 256 MaxConnectionsPerChild 1000 # For event MPM (recommended for high traffic, similar to nginx)StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadLimit 64 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 1000 # For worker MPM (hybrid approach)StartServers 3 MinSpareThreads 75 MaxSpareThreads 250 ThreadLimit 64 ThreadsPerChild 25 MaxRequestWorkers 400 MaxConnectionsPerChild 1000
KeepAlive settings:
KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 15
Memory and cache settings:
# File cache CacheEnable disk / CacheDefaultExpire 3600 CacheMaxFileSize 1000000 CacheRoot /var/cache/apache24 # Memory settings RLimitMEM 512000 1024000 # Min and Max memory in bytes
Compression (mod_deflate):
# Enable deflate module (usually already loaded)AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript application/javascript # Don't compress images SetOutputFilter DEFLATE SetEnv no-gzip 1
Enable caching headers:
ExpiresActive On ExpiresByType text/html "access plus 1 hour" ExpiresByType text/css "access plus 1 week" ExpiresByType text/javascript "access plus 1 week" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month"
Create a new website:
# 1. Create directory structure
mkdir -p /usr/local/www/mysite.com/{public_html,logs,cgi-bin}
# 2. Create basic index.html
cat > /usr/local/www/mysite.com/public_html/index.html << 'EOF'
Welcome to mysite.com
mysite.com
EOF
# 3. Create virtual host configuration
cat > /usr/local/etc/apache24/Includes/mysite.com.conf << 'EOF'
ServerName mysite.com
ServerAlias www.mysite.com
DocumentRoot /usr/local/www/mysite.com/public_html
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
ErrorLog /var/log/apache24/mysite.com-error.log
CustomLog /var/log/apache24/mysite.com-access.log common
EOF
# 4. Test and restart Apache
apachectl -t && service apache24 restart
Enable .htaccess files:
# In your virtual host or directory configurationOptions Indexes FollowSymLinks AllowOverride All # This enables .htaccess Require all granted
Password protect a directory:
# 1. Create password file htpasswd -c /usr/local/etc/apache24/.htpasswd admin # You'll be prompted for the password # 2. Configure directory in virtual hostAuthType Basic AuthName "Restricted Area" AuthUserFile /usr/local/etc/apache24/.htpasswd Require valid-user
Enable CGI scripts:
# 1. Ensure CGI module is loaded (usually enabled by default) # LoadModule cgid_module modules/mod_cgid.so # 2. Configure CGI directoryOptions +ExecCGI AddHandler cgi-script .cgi .pl Require all granted # 3. Create a test CGI script cat > /usr/local/www/mysite.com/cgi-bin/test.cgi << 'EOF' #!/bin/sh echo "Content-type: text/html" echo "" echo "CGI Test Successful
" EOF chmod +x /usr/local/www/mysite.com/cgi-bin/test.cgi # 4. Test in browser: http://mysite.com/cgi-bin/test.cgi
Custom error pages:
# In your virtual host configuration ErrorDocument 401 /errors/401.html ErrorDocument 403 /errors/403.html ErrorDocument 404 /errors/404.html ErrorDocument 500 /errors/500.html # Create error directory and pages mkdir -p /usr/local/www/mysite.com/errors # Create your custom error pages in this directory
Disable directory listing:
Options -Indexes
.htaccess files allow directory-level configuration without editing the main Apache configuration.
Enable .htaccess: Make sure AllowOverride All is set for the directory.
Common .htaccess examples:
Basic authentication:
AuthType Basic AuthName "Restricted Access" AuthUserFile /usr/local/www/.htpasswd Require valid-user
Rewrite URLs:
RewriteEngine On
RewriteRule ^old-page.html$ /new-page.html [R=301,L]
# Remove .html extension
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1.html [L]
Custom error documents:
ErrorDocument 404 /custom-404.html ErrorDocument 403 /custom-403.html
Prevent hotlinking:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$ [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www\)?example.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [F,NC]
Redirect www to non-www:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.example.com [NC]
RewriteRule ^(.*)$ http://example.com/$1 [L,R=301]
Redirect HTTP to HTTPS:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Cache control:
Header set Cache-Control "no-cache, no-store, must-revalidate" Header set Cache-Control "public, max-age=31536000"
Security is critical for web servers exposed to the internet. These recommendations apply to both nginx and Apache.
General Security Best Practices:
Nginx Security Configuration:
# In nginx.conf
user www; # Run as www user, not root
# Hide nginx version in error pages and headers
server_tokens off;
# Disable server version in response headers
more_clear_headers 'Server';
# Limit request methods
if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|OPTIONS)$ ) {
return 405;
}
# Block access to hidden files (starting with .)
location ~ /\. {
deny all;
return 404;
}
# Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;
# Enable XSS protection
add_header X-XSS-Protection "1; mode=block" always;
# Prevent content-type sniffing for uploads
location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|js|pdf|txt|html)$ {
add_header X-Content-Type-Options "nosniff";
}
Apache Security Configuration:
# Run as non-root user User www Group www # Hide Apache version ServerTokens Prod ServerSignature Off # Disable .htaccess in root directory (if not needed)AllowOverride None Require all denied # Protect configuration files Require all denied # Limit request methodsRequire all denied # Disable directory listing Options -Indexes # Security headers Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set X-XSS-Protection "1; mode=block"
Rate Limiting (Nginx):
# Limit connections from a single IP
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 20;
# Limit request rate
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
limit_req zone=req_limit burst=20 nodelay;
# Apply to specific location
location /login {
limit_req zone=req_limit burst=5;
}
Rate Limiting (Apache):
# Requires mod_evasive or mod_security # Example with mod_evasive (install via mports)DOSHashTableSize 3097 DOSPageCount 2 DOSSiteCount 50 DOSPageInterval 1 DOSSiteInterval 1 DOSBlockingPeriod 60
File Upload Security:
# Nginx client_max_body_size 10M; # Limit upload size client_body_temp_path /tmp/nginx_upload; # Apache LimitRequestBody 10485760 # 10MB limit
Both nginx and Apache can be configured as load balancers to distribute traffic across multiple backend servers.
Nginx Load Balancing:
# Define upstream servers
upstream backend_servers {
# Weighted round-robin
server 192.168.1.101:8000 weight=3;
server 192.168.1.102:8000;
server 192.168.1.103:8000;
# Health check
# check interval=5000 rise=2 fall=3 timeout=3000 type=http;
# check_http_send "HEAD / HTTP/1.0\r\n\r\n";
# check_http_expect_alive http_2xx http_3xx;
}
# Round-robin (default)
upstream round_robin {
server 192.168.1.101:8000;
server 192.168.1.102:8000;
}
# IP hash (sticky sessions)
upstream sticky_sessions {
ip_hash;
server 192.168.1.101:8000;
server 192.168.1.102:8000;
}
# Least connections
upstream least_conn {
least_conn;
server 192.168.1.101:8000;
server 192.168.1.102:8000;
}
# Use in server block
server {
listen 80;
server_name loadbalanced.example.com;
location / {
proxy_pass http://backend_servers;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Apache Load Balancing (with mod_proxy_balancer):
# Enable required modules LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so # Configure balancerBalancerMember http://192.168.1.101:8000 BalancerMember http://192.168.1.102:8000 BalancerMember http://192.168.1.103:8000 # Sticky session using route ProxySet stickysession=ROUTEID # Virtual host using load balancerServerName loadbalanced.example.com ProxyPass / balancer://mycluster/ ProxyPassReverse / balancer://mycluster/
Health checks and failover:
# Nginx with health checks (requires nginx upstream check module)
upstream backend_with_healthcheck {
server 192.168.1.101:8000 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8000 max_fails=3 fail_timeout=30s;
server 192.168.1.103:8000 backup;
}
# Apache with failover
BalancerMember http://192.168.1.101:8000
BalancerMember http://192.168.1.102:8000
BalancerMember http://192.168.1.103:8000 status=+H
ProxySet failonstatus=500,502,503,504
Proper monitoring and logging are essential for troubleshooting and performance optimization.
Nginx Logging:
# Custom log format
http {
log_format custom_log '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time';
access_log /var/log/nginx/access.log custom_log;
error_log /var/log/nginx/error.log warn;
}
# Per-server logging
server {
access_log /var/log/nginx/example.com-access.log;
error_log /var/log/nginx/example.com-error.log;
}
# Disable logging for specific requests
location /health-check {
access_log off;
}
Apache Logging:
# Custom log format
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" extended
# Use custom log format
CustomLog /var/log/apache24/access.log extended
ErrorLog /var/log/apache24/error.log
# Per-virtual-host logging
ServerName example.com
CustomLog /var/log/apache24/example.com-access.log combined
ErrorLog /var/log/apache24/example.com-error.log
Log rotation:
# Both nginx and Apache respect newsyslog configuration # Edit /etc/newsyslog.conf # Example log rotation entry /var/log/nginx/*.log www:www 640 7 * @T00 JC /var/log/apache24/*.log www:www 640 7 * @T00 JC # Or use logrotate (install via mports) mport install logrotate
Real-time log monitoring:
# Monitor access log in real-time
tail -f /var/log/nginx/access.log
# Filter for errors
tail -f /var/log/nginx/error.log | grep error
# Monitor Apache logs
tail -f /var/log/apache24/access.log
# Count requests per minute
tail -n 1000 /var/log/nginx/access.log | awk '{print $4}' | cut -d: -f2,3 | uniq -c
Access statistics:
# Install log analysis tools mport install awstats mport install goaccess # Run awstats awstats -config=nginx -update # Run goaccess (real-time web log analyzer) goaccess /var/log/nginx/access.log --log-format=COMBINED
Monitoring with htop/htop:
# Install htop mport install htop # Monitor web server processes htop # Press F5 to sort by CPU usage
Status pages:
# Nginx status page (requires ngx_http_stub_status_module)
location /nginx-status {
stub_status on;
access_log off;
allow 127.0.0.1;
allow 192.168.1.0/24;
deny all;
}
# Apache status page (requires mod_status)
SetHandler server-status
Require local
# Or for specific IPs:
# Require ip 192.168.1.100
# Enable extended status
ExtendedStatus On
Common Issues and Solutions:
"Address already in use" error:
# Check what's using port 80 netstat -an | grep :80 # Kill the conflicting process kill -9 [PID] # Or use sockstat sockstat -l | grep :80
Configuration syntax errors:
# Test configuration before applying nginx -t # If there's an error, it will tell you the file and line number
Permission denied errors:
# Check file permissions ls -la /usr/local/www/example.com # Ensure nginx worker process has access chown -R www:www /usr/local/www/example.com chmod -R 755 /usr/local/www/example.com
502 Bad Gateway (proxy issues):
# Check if backend server is running netstat -an | grep 8000 # Check proxy configuration # Ensure proxy_pass directive points to correct backend # Test connection to backend curl http://localhost:8000
403 Forbidden:
# Check directory permissions ls -la /usr/local/www/example.com # Check nginx configuration for the location # Ensure root or alias directives are correct # Check if index files exist ls -la /usr/local/www/example.com/index.html
"Address already in use" error:
# Check what's using port 80 netstat -an | grep :80 # Stop Apache first service apache24 stop # Then start again service apache24 start
Syntax errors:
# Test configuration apachectl -t # If there's an error, it will tell you the file and line number
Permission denied:
# Check file permissions ls -la /usr/local/www/example.com # Ensure Apache user has access chown -R www:www /usr/local/www/example.com chmod -R 755 /usr/local/www/example.com # Check SELinux/AppArmor (not typically on MidnightBSD)
Module not loaded:
# Check loaded modules httpd -M # Uncomment or add LoadModule directive in httpd.conf LoadModule rewrite_module modules/mod_rewrite.so # Restart Apache service apache24 restart
PHP not working:
# Ensure PHP module is loaded LoadModule php7_module modules/libphp7.so # Check PHP handler configurationSetHandler application/x-httpd-php # Or for PHP-FPM # LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so # ProxyPassMatch ^/(.*\.php)$ fcgi://127.0.0.1:9000/usr/local/www/$1
Debugging tools:
# Check open files by Apache fstat | grep httpd # Check network connections netstat -an | grep httpd # Check Apache modules httpd -M # Check nginx processes ps aux | grep nginx # Check nginx connections nginx -T # Show full configuration with all includes
Debug log level:
# Nginx - set error_log level error_log /var/log/nginx/error.log debug; # Apache - set LogLevel echo "LogLevel debug" >> /usr/local/etc/apache24/httpd.conf service apache24 restart