Web Server Configuration

Web Server Configuration

Introduction

Setting 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.

Choosing Between Nginx and Apache

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

Installation

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:

Basic Configuration

The 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

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;
}

HTTPS with Let's Encrypt

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;

Performance Tuning

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";
}

Reverse Proxy Setup

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;
    }
}

Common Nginx Tasks

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

Installation

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:

Basic Configuration

The 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 configuration

    Options 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:

Common 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

Virtual Hosts

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.conf


    ServerAdmin 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 common



    ServerAdmin 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 80

    ServerName example.com
    DocumentRoot /usr/local/www/example-http


# Admin site on port 8080

    ServerName example.com
    DocumentRoot /usr/local/www/example-admin

Default virtual host:

# First virtual host defined becomes the default

    ServerName default.example.com
    DocumentRoot /usr/local/www/default
    
    # Or redirect all undefined hosts
    Redirect permanent / http://example.com/

HTTPS Configuration

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"

Performance Tuning

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"

Common Apache Tasks

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 configuration

    Options 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 host

    AuthType 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 directory

    Options +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 Configuration

.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 Hardening

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 methods

    Require 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

Load Balancing

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 balancer

    BalancerMember 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 balancer

    ServerName 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

Monitoring and Logging

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

Troubleshooting

Common Issues and Solutions:

Nginx Troubleshooting

"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
Apache Troubleshooting

"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 configuration

    SetHandler 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