← Back to DevBytes

openSUSE Performance Tuning for Web Servers

Introduction to openSUSE Performance Tuning for Web Servers

openSUSE is a robust, enterprise-grade Linux distribution that powers many production web servers around the world. Whether you are running Apache, Nginx, or a combination of both, the default installation is optimized for general-purpose use rather than high-traffic web serving. Performance tuning transforms a stock openSUSE system into a lean, efficient web server capable of handling thousands of concurrent connections while maintaining low latency and high throughput.

This tutorial covers the essential performance tuning techniques specific to openSUSE, including kernel parameters, network stack optimization, file system configuration, web server tuning, and monitoring strategies. By the end, you will have a complete playbook for squeezing maximum performance from your openSUSE web server.

Why Performance Tuning Matters

Performance tuning is not just about raw speed. It affects every aspect of your web server's operation:

Prerequisites

Before beginning, ensure you have the following:

System-Level Kernel Tuning

The Linux kernel exposes hundreds of tunable parameters through the /proc/sys virtual file system. openSUSE uses sysctl to manage these parameters persistently. Let us start with the most impactful kernel settings for web servers.

Network Stack Optimization

The network stack is the foundation of web server performance. The following settings optimize connection handling, buffer sizes, and TCP behavior.

# Create a custom sysctl configuration file
sudo nano /etc/sysctl.d/99-webserver.conf

Add the following configuration:

# Increase the maximum number of connections the kernel will accept
net.core.somaxconn = 65535

# Increase the connection backlog queue
net.core.netdev_max_backlog = 65535

# Increase the number of available file descriptors
fs.file-max = 2097152

# Enable TCP Fast Open for reduced latency
net.ipv4.tcp_fastopen = 3

# Enable and tune TCP window scaling
net.ipv4.tcp_window_scaling = 1
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# Reduce TCP keepalive probes for faster dead connection cleanup
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5

# Enable TCP SYN cookies to prevent SYN flood attacks
net.ipv4.tcp_syncookies = 1

# Increase SYN backlog
net.ipv4.tcp_max_syn_backlog = 65535

# Reduce TIME_WAIT socket reuse and recycling settings
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# Disable ICMP redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Enable forward error correction and congestion control
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq

Apply the changes immediately:

sudo sysctl -p /etc/sysctl.d/99-webserver.conf

Verify that BBR congestion control is available and active:

# Check available congestion control algorithms
sysctl net.ipv4.tcp_available_congestion_control

# Verify BBR is in use
sysctl net.ipv4.tcp_congestion_control

If BBR is not available, load the kernel module:

sudo modprobe tcp_bbr
echo "tcp_bbr" | sudo tee /etc/modules-load.d/tcp_bbr.conf

File Descriptor Limits

Web servers handle many simultaneous connections, each consuming a file descriptor. The default limits are often too low for production use.

# Edit the system limits configuration
sudo nano /etc/security/limits.conf

Add the following lines:

# Web server file descriptor limits
* soft nofile 1048576
* hard nofile 1048576
* soft nproc 65535
* hard nproc 65535
root soft nofile 1048576
root hard nofile 1048576

For systemd-managed services, you also need to configure limits in the service unit files or globally:

# Create a systemd override directory for global limits
sudo mkdir -p /etc/systemd/system.conf.d

sudo nano /etc/systemd/system.conf.d/limits.conf
[Manager]
DefaultLimitNOFILE=1048576
DefaultLimitNPROC=65535

Reload systemd and restart your web server:

sudo systemctl daemon-reexec
sudo systemctl restart nginx
# or
sudo systemctl restart apache2

Memory and Swap Tuning

Memory management is critical for web servers. Improper swap behavior can cause severe latency spikes when the system pages memory to disk.

Swappiness Configuration

The vm.swappiness parameter controls how aggressively the kernel swaps anonymous memory pages to disk. For web servers, a low value is preferred to keep application data in RAM.

# Set swappiness to a low value (default is 60)
sudo sysctl -w vm.swappiness=10

# Make it persistent
echo "vm.swappiness = 10" | sudo tee -a /etc/sysctl.d/99-webserver.conf

# Reduce vfs cache pressure to keep directory and inode cache
echo "vm.vfs_cache_pressure = 50" | sudo tee -a /etc/sysctl.d/99-webserver.conf

# Disable overcommit to prevent OOM killer from terminating web server processes
echo "vm.overcommit_memory = 1" | sudo tee -a /etc/sysctl.d/99-webserver.conf

Transparent Huge Pages

Transparent Huge Pages (THP) can cause latency issues on web servers due to defragmentation. Disabling THP or setting it to madvise is recommended.

# Check current THP status
cat /sys/kernel/mm/transparent_hugepage/enabled

# Set to madvise (applications can opt-in)
echo madvise | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

# Make it persistent using a systemd service
sudo nano /etc/systemd/system/disable-thp.service
[Unit]
Description=Disable Transparent Huge Pages
After=sysinit.target local-fs.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo madvise > /sys/kernel/mm/transparent_hugepage/enabled"
RemainAfterExit=yes

[Install]
WantedBy=basic.target
sudo systemctl enable disable-thp.service
sudo systemctl start disable-thp.service

Nginx Performance Tuning

Nginx is the most popular web server on openSUSE for high-performance workloads. The following optimizations target connection handling, worker processes, and caching.

Worker Process and Connection Configuration

sudo nano /etc/nginx/nginx.conf
# Set worker processes to match CPU cores
worker_processes auto;
worker_cpu_affinity auto;

# Increase worker connections
worker_rlimit_nofile 1048576;

events {
    worker_connections 65535;
    multi_accept on;
    use epoll;
}

http {
    # Enable sendfile for efficient file transfers
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    # Optimize keepalive connections
    keepalive_timeout 30;
    keepalive_requests 1000;

    # Buffer sizes
    client_body_buffer_size 16k;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 8k;
    client_max_body_size 64m;

    # Connection reset timeout
    reset_timedout_connection on;

    # Disable unnecessary tokens
    server_tokens off;

    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 256;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/javascript
        application/json
        application/xml
        application/xml+rss
        application/xhtml+xml
        application/x-javascript
        image/svg+xml;

    # Open file cache for static assets
    open_file_cache max=10000 inactive=60s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    # Include server configurations
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/vhosts.d/*.conf;
}

Upstream and Proxy Tuning

When Nginx acts as a reverse proxy, upstream connection settings significantly impact performance:

upstream backend {
    server 127.0.0.1:8080;
    keepalive 64;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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_connect_timeout 5s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
        proxy_buffering on;
        proxy_buffer_size 16k;
        proxy_buffers 8 32k;
        proxy_busy_buffers_size 64k;
    }
}

Static Asset Caching

server {
    listen 80;
    server_name static.example.com;
    root /srv/www/static;

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
        sendfile on;
        tcp_nopush on;
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

Apache Performance Tuning

Apache remains widely used on openSUSE. The key to Apache performance is selecting the right Multi-Processing Module (MPM) and tuning it properly.

Selecting the Event MPM

The Event MPM is the most efficient Apache MPM for most workloads. It uses a hybrid approach with a small number of processes and many threads per process.

# On openSUSE, enable the event MPM
sudo a2enmod mpm_event

# Disable the prefork MPM if enabled
sudo a2dismod mpm_prefork

# Enable necessary modules
sudo a2enmod headers
sudo a2enmod expires
sudo a2enmod deflate
sudo a2enmod http2

MPM Event Configuration

sudo nano /etc/apache2/mods-enabled/mpm_event.conf
<IfModule mpm_event_module>
    StartServers 3
    MinSpareThreads 75
    MaxSpareThreads 250
    ThreadsPerChild 25
    MaxRequestWorkers 400
    MaxConnectionsPerChild 10000
    AsyncRequestWorkerFactor 2
    ListenBacklog 511
</IfModule>

The MaxConnectionsPerChild setting is particularly important. Setting it to a non-zero value prevents memory leaks from accumulating by recycling worker processes after they handle a set number of requests.

Apache Keep-Alive and Compression

sudo nano /etc/apache2/server-tuning.conf
# Keep-Alive settings
KeepAlive On
MaxKeepAliveRequests 1000
KeepAliveTimeout 5

# Compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json application/xml
    DeflateCompressionLevel 6
    DeflateBufferSize 8096
</IfModule>

# Cache settings
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType text/html "access plus 5 minutes"
</IfModule>

Restart Apache to apply changes:

sudo systemctl restart apache2

File System and Disk I/O Tuning

Disk I/O is often the bottleneck for web servers serving static content or writing logs. openSUSE defaults to the Btrfs or ext4 file systems, both of which can be tuned for web workloads.

Mount Options for Web Directories

Optimize mount options for directories containing web content and logs:

# Check current mount options
mount | grep /srv

# Edit fstab for persistent mount options
sudo nano /etc/fstab

Add the following options for web content partitions:

/dev/sdb1  /srv/www  ext4  defaults,noatime,nodiratime,data=writeback,barrier=0  0  2

For Btrfs, use these options:

/dev/sdb1  /srv/www  btrfs  defaults,noatime,compress=zstd:3,space_cache=v2  0  0

The noatime option prevents the file system from updating access times on every read, significantly reducing write I/O. The compress=zstd:3 option for Btrfs provides transparent compression that reduces disk usage and can improve I/O throughput for compressible data.

I/O Scheduler Tuning

The I/O scheduler controls how disk I/O requests are ordered. For SSDs and NVMe drives, the none or mq-deadline scheduler is optimal.

# Check current scheduler
cat /sys/block/sda/queue/scheduler

# Set the scheduler to none for NVMe/SSD
echo none | sudo tee /sys/block/nvme0n1/queue/scheduler

# For SATA SSDs, use mq-deadline
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler

# Make it persistent with a udev rule
sudo nano /etc/udev/rules.d/60-io-scheduler.rules
# Set scheduler based on device type
ACTION=="add|change", KERNEL=="nvme[0-9]*n[0-9]*", ATTR{queue/scheduler}="none"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
sudo udevadm control --reload-rules
sudo udevadm trigger

Read-Ahead and Queue Depth

# Increase read-ahead for sequential reads (useful for log files and static assets)
sudo blockdev --setra 4096 /dev/sda

# Increase queue depth for NVMe
echo 1024 | sudo tee /sys/block/nvme0n1/queue/nr_requests

PHP-FPM Tuning for Dynamic Content

If your web server runs PHP applications, PHP-FPM configuration is critical. Poorly tuned PHP-FPM can exhaust memory and cause 502 errors.

sudo nano /etc/php8/fpm/php-fpm.conf
[global]
error_log = /var/log/php8/fpm-error.log
log_level = warning
emergency_restart_threshold = 10
emergency_restart_interval = 1m
process_control_timeout = 10s
daemonize = yes

Configure the pool settings:

sudo nano /etc/php8/fpm/pool.d/www.conf
[www]
user = wwwrun
group = www
listen = /run/php-fpm/www.sock
listen.owner = wwwrun
listen.group = www
listen.mode = 0660

# Use dynamic process management
pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18
pm.max_requests = 1000

# Slow log for debugging
slowlog = /var/log/php8/slow.log
request_slowlog_timeout = 5s

# Status page for monitoring
pm.status_path = /fpm-status
ping.path = /fpm-ping

Calculate the optimal pm.max_children value based on available memory:

# Calculate based on average PHP process memory usage
# Formula: max_children = (Total RAM - RAM for other services) / Average PHP process size

# Check average memory usage of PHP-FPM processes
ps -ylC php-fpm --sort:rss | awk '{sum+=$8; count++} END {print "Average memory per process: " sum/count/1024 " MB"}'

Also tune the PHP php.ini for performance:

sudo nano /etc/php8/cli/php.ini
; OPcache settings
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 20000
opcache.revalidate_freq = 60
opcache.fast_shutdown = 1
opcache.enable_cli = 0

; Realpath cache
realpath_cache_size = 4096k
realpath_cache_ttl = 600

; Memory and execution limits
memory_limit = 256M
max_execution_time = 30
max_input_time = 60
sudo systemctl restart php-fpm

Database Connection Optimization

Web servers often connect to databases. Connection pooling and caching reduce overhead significantly.

Redis as a Session Handler

# Install Redis on openSUSE
sudo zypper install redis

# Enable and start Redis
sudo systemctl enable --now redis

# Configure PHP to use Redis for sessions
sudo nano /etc/php8/fpm/php.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6373?auth=yourpassword&timeout=2&database=1"
session.gc_maxlifetime = 1440
session.cookie_lifetime = 0

MySQL/MariaDB Connection Tuning

sudo nano /etc/my.cnf.d/server.cnf
[mysqld]
# Connection settings
max_connections = 500
max_user_connections = 400
wait_timeout = 60
interactive_timeout = 60

# Buffer pool (set to 70-80% of available RAM for dedicated DB servers)
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 4
innodb_log_file_size = 512M
innodb_log_buffer_size = 64M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# Query cache (if using MySQL 5.7 or MariaDB)
query_cache_type = 0
query_cache_size = 0

# Temporary tables
tmp_table_size = 64M
max_heap_table_size = 64M

# Connection pooling
thread_cache_size = 100
table_open_cache = 4000
open_files_limit = 65535

Firewall and Security Tuning

openSUSE uses firewalld by default. While security is essential, overly restrictive or poorly configured firewalls can impact performance.

Optimizing firewalld for Web Traffic

# Check firewalld status
sudo firewall-cmd --state

# Add HTTP and HTTPS services permanently
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# Reload firewall
sudo firewall-cmd --reload

# Enable connection tracking optimization
sudo nano /etc/modprobe.d/conntrack.conf
# Increase connection tracking table size
options nf_conntrack hashsize=262144
# Apply the new conntrack settings
sudo sysctl -w net.netfilter.nf_conntrack_max=1048576
echo "net.netfilter.nf_conntrack_max = 1048576" | sudo tee -a /etc/sysctl.d/99-webserver.conf

Rate Limiting with Nginx

Application-level rate limiting protects your server from abuse and ensures fair resource distribution:

# Define rate limiting zones in http block
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=5r/s;
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;

server {
    listen 80;
    server_name example.com;

    # Apply connection limiting
    limit_conn conn_per_ip 20;

    location / {
        limit_req zone=general burst=20 nodelay;
        proxy_pass http://backend;
    }

    location /api/ {
        limit_req zone=api burst=10 nodelay;
        proxy_pass http://backend;
    }
}

Monitoring and Benchmarking

Tuning without measurement is guesswork. Establish baselines and continuously monitor performance to validate your changes.

System Monitoring Tools

Install essential monitoring tools on openSUSE:

sudo zypper install htop iotop sysstat nethogs perf

Enable sysstat for historical performance data:

sudo systemctl enable --now sysstat

Use sar to collect and view performance statistics:

# View CPU usage
sar -u 1 10

# View memory usage
sar -r 1 10

# View network statistics
sar -n DEV 1 10

# View disk I/O
sar -d 1 10

Benchmarking with Apache Bench

# Install Apache Bench
sudo zypper install apache2-utils

# Basic benchmark
ab -n 10000 -c 100 http://localhost/

# Benchmark with keep-alive
ab -n 10000 -c 100 -k http://localhost/

# Benchmark with custom headers
ab -n 10000 -c 100 -H "Accept-Encoding: gzip,deflate" http://localhost/

Benchmarking with wrk

For more advanced benchmarking, wrk provides detailed latency distribution:

# Install wrk from source
cd /tmp
git clone https://github.com/wg/wrk.git
cd wrk
make
sudo cp wrk /usr/local/bin/

# Run a 30-second benchmark with 100 connections and 10 threads
wrk -t10 -c100 -d30s http://localhost/

# Run with a Lua script for POST requests
wrk -t10 -c100 -d30s -s post.lua http://localhost/api

Example Lua script for POST testing:

-- post.lua
wrk.method = "POST"
wrk.body = '{"key":"value"}'
wrk.headers["Content-Type"] = "application/json"

Real-Time Monitoring with Prometheus and Grafana

For production servers, set up continuous monitoring:

# Install Prometheus node exporter
sudo zypper install golang-github-prometheus-node_exporter
sudo systemctl enable --now prometheus-node_exporter

# Install Grafana (add repository first)
sudo zypper ar https://packages.grafana.com/oss/rpm/grafana.repo
sudo zypper refresh
sudo zypper install grafana
sudo systemctl enable --now grafana-server

Best Practices

Enabling Persistent Journal Logging

sudo nano /etc/systemd/journald.conf
[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=500M
SystemKeepFree=1G
MaxFileSec=1month
sudo systemctl restart systemd-journald

Automating Tuning with Configuration Management

For servers that are rebuilt frequently or managed at scale, automate your tuning configuration using Ansible:

---
- name: Tune openSUSE web server
  hosts: webservers
  become: yes
  tasks:
    - name: Deploy sysctl configuration
      copy:
        src: files/99-webserver.conf
        dest: /etc/sysctl.d/99-webserver.conf
      notify: apply sysctl

    - name: Deploy limits configuration
      copy:
        src: files/limits.conf
        dest: /etc/security/limits.conf

    - name: Deploy systemd limits
      copy:
        src: files/systemd-limits.conf
        dest: /etc/systemd/system.conf.d/limits.conf
      notify: reload systemd

    - name: Deploy THP service
      copy:
        src: files/disable-thp.service
        dest: /etc/systemd/system/disable-thp.service
      notify: enable thp service

    - name: Deploy nginx configuration
      copy:
        src: files/nginx.conf
        dest: /etc/nginx/nginx.conf
      notify: restart nginx

  handlers:
    - name: apply sysctl
      command: sysctl -p /etc/sysctl.d/99-webserver.conf

    - name: reload systemd
      command: systemctl daemon-reexec

    - name: enable thp service
      systemd:
        name: disable-thp
        enabled: yes
        state: started
        daemon_reload: yes

    - name: restart nginx
      service:
        name: nginx
        state: restarted

Troubleshooting Common Issues

Too Many Open Files

If you see "Too many open files" errors, check and increase file descriptor limits:

# Check current limits for the web server process
cat /proc/$(pgrep -o nginx)/limits | grep "Max open files"

# Check system-wide file descriptor usage
cat /proc/sys/fs/file-nr

Connection Refused Under Load

This often indicates the backlog queue is full or the application cannot accept connections fast enough:

# Check current listen backlog
ss -lnt | grep :80

# Check for dropped connections
netstat -s | grep -i "listen"

High Memory Usage

# Check memory usage by process
ps aux --sort=-%mem | head -20

# Check for memory leaks
valgrind --leak-check=full /usr/sbin/nginx -g "daemon off;"

Slow Response Times

# Check disk I/O wait
iostat -x 1 10

# Check network latency
mtr -n example.com

# Profile the application
perf record -g -p $(pgrep -o nginx) -- sleep 30
perf report

Conclusion

Performance tuning an openSUSE web server is a systematic process that spans multiple layers of the system stack, from kernel parameters and network configuration to web server settings and application-level optimizations. The techniques covered in this tutorial provide a comprehensive foundation, but remember that tuning is an iterative process. Every workload is unique, and the optimal configuration depends on your specific traffic patterns, hardware, and application requirements. Start with the kernel and network stack optimizations, then move to web server and application tuning, always measuring the impact of each change with proper benchmarking tools. Establish continuous monitoring to catch regressions early, and use configuration management to ensure your tuning is reproducible across all your servers. With careful application of these techniques, your openSUSE web server will be well-equipped to handle high traffic loads efficiently, reliably, and cost-effectively.

— Ad —

Google AdSense will appear here after approval

← Back to all articles