Skip to content

Web Server

Apache httpd

Default configuration

Modules to enable:

  • ssl
  • cache
  • cache-socache
  • socache_shmcb
  • proxy
  • proxy connect
  • proxy http
  • rewrite

Include the SSL config in httpd.config.

xml
<VirtualHost *:443>
        ServerAdmin [email protected]
        ServerName dashboard.example.com
        ProxyRequests Off
        ProxyPreserveHost On
        ProxyPass / http://10.148.0.3:9100/
        ProxyPassReverse / http://10.148.0.3:9100/
        SSLEngine On
        SSLCertificateFile /usr/local/apache2/conf/vidp-cert.pem
        SSLCertificateKeyFile /usr/local/apache2/conf/vidp-key.pem
        SSLCertificateChainFile /usr/local/apache2/conf/cloudflare-ca.pem
        RewriteEngine On
        RewriteCond %{HTTP:Upgrade} websocket [NC]
        RewriteCond %{HTTP:Connection} upgrade [NC]
        RewriteRule ^/?(.*) "ws://10.148.0.3:9100/$1" [P,L]

        ErrorLog "logs/vidp-dash-ssl-error.log"
        CustomLog "logs/vidp-dash-ssl-access.log" combined
</VirtualHost>

Verify config

sh
apachectl configtest

Nginx

Global production settings

Add these process-level defaults in the main nginx.conf:

nginx
user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 4096;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    server_tokens off;
    client_max_body_size 20M;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;
}

SSL configuration

nginx
server {
    listen  443 ssl;
    listen  [::]:443;
    # ssl   on;
    ssl_certificate /etc/nginx/cert.pem;
    ssl_certificate_key /etc/nginx/key.pem;

    server_name domain.name;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # set client body size to 100 MB #
    client_max_body_size 100M;

    location / {
      root   /usr/share/nginx/html;
      index  index.html;
      # line below required if use for single page application
      try_files $uri $uri/ /index.html;
    }
}

Proxy configuration

nginx
server {
    listen  80;
    listen  [::]:80;

    server_name domain.com;
    
    # Maximum file size can be transfer
    # client_max_body_size 10M;

    access_log /var/log/nginx/domain.access.log;
    error_log /var/log/nginx/domain.error.log;
    location / {
      proxy_pass http://172.18.88.100:8080;
    }
}

Install Let's Encrypt:

sh
sudo apt-get install certbot
sudo apt-get install python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

sudo certbot certonly -d another.com.my,www.another.com.my
sudo certbot certificates

Template:

nginx
server {
  if ($host = domain.com) {
      return 301 https://$host$request_uri;
  } 
  listen 80 ;
  listen [::]:80 ;
  server_name domain.com;
  return 404; 
}
server {
  # Add index.php to the list if you are using PHP
  index index.html index.htm;
  server_name domain.com; 
  location / {
    proxy_pass http://localhost:8090;
    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_set_header X-Forwarded-Port 443;
    proxy_set_header X-Forwarded-Host  $host;
  }
  
  # pass PHP scripts to FastCGI server
  listen [::]:443 ssl;
  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Production-ready recommendations

Nginx reverse proxy baseline

nginx
server_tokens off;
client_max_body_size 20M;
keepalive_timeout 65;
send_timeout 30;

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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;

Security headers:

nginx
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

TLS recommendation:

nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_prefer_server_ciphers off;

Apache reverse proxy baseline

apache
ServerTokens Prod
ServerSignature Off
ProxyTimeout 60
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500

Operational checklist:

  • rotate access and error logs
  • terminate TLS at the web server unless a load balancer already does it
  • expose only 80 and 443 publicly
  • keep upstream app servers on private interfaces