๐ Web Server Setup with Apache on AlmaLinux: Host Like a Pro
Remember paying $100/month for basic web hosting? ๐ธ Not anymore! With Apache on AlmaLinux, you can host unlimited websites on your own server. I learned this when my hosting bill hit $500/month for 20 sites. Now I run 100+ sites on a single server that costs $50/month. Today Iโm showing you how to set up Apache like a pro - virtual hosts, SSL, caching, the works! Letโs turn your AlmaLinux box into a web hosting powerhouse! ๐
๐ค Why Apache Still Rules the Web
Nginx is trendy, but Apache is legendary! Hereโs why itโs still king:
- ๐ Most Popular - Powers 30% of the internet
- ๐ง Super Flexible - .htaccess for easy config
- ๐ฏ Module System - Add features without recompiling
- ๐ Massive Community - Solutions for everything
- ๐ PHP Integration - Perfect with mod_php
- ๐ก๏ธ Battle Tested - 25+ years of reliability
Fun fact: I tried switching to Nginx once. Spent a week converting .htaccess rules. Switched back to Apache in an hour! ๐
๐ฏ What You Need
Before we start serving websites, ensure you have:
- โ AlmaLinux system with public IP
- โ Root or sudo access
- โ Domain name (optional for testing)
- โ 30 minutes to become a web hosting pro
- โ Coffee (web servers run on coffee! โ)
๐ Step 1: Installing and Configuring Apache
Letโs get Apache up and running!
Install Apache
# Install Apache (httpd in RHEL world)
sudo dnf install -y httpd
# Install useful modules
sudo dnf install -y mod_ssl mod_security mod_evasive
# Enable and start Apache
sudo systemctl enable --now httpd
# Check status
sudo systemctl status httpd
# Verify installation
httpd -v
# Check loaded modules
httpd -M
Basic Configuration
# Main config file
sudo nano /etc/httpd/conf/httpd.conf
# Key settings to modify:
ServerRoot "/etc/httpd"
Listen 80
# Server identification
ServerAdmin [email protected]
ServerName server.example.com:80
# Performance settings
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
# MPM (Multi-Processing Module) tuning
<IfModule mpm_prefork_module>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
MaxRequestWorkers 250
MaxConnectionsPerChild 4000
</IfModule>
# Hide Apache version
ServerTokens Prod
ServerSignature Off
# Default document root
DocumentRoot "/var/www/html"
# Directory permissions
<Directory "/var/www">
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Configure Firewall
# Open HTTP and HTTPS ports
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
# Verify
sudo firewall-cmd --list-all
๐ง Step 2: Virtual Hosts Configuration
Host multiple websites on one server!
Create Virtual Host
# Create directory structure
sudo mkdir -p /var/www/site1.com/{public_html,logs,ssl}
sudo mkdir -p /var/www/site2.com/{public_html,logs,ssl}
# Set permissions
sudo chown -R apache:apache /var/www/site1.com
sudo chmod -R 755 /var/www/site1.com
# Create test page
cat > /var/www/site1.com/public_html/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Site1.com!</title>
<style>
body { font-family: Arial; text-align: center; padding: 50px; }
h1 { color: #333; }
.info { background: #f0f0f0; padding: 20px; border-radius: 10px; margin: 20px auto; max-width: 600px; }
</style>
</head>
<body>
<h1>๐ Site1.com is Live!</h1>
<div class="info">
<p>Powered by Apache on AlmaLinux</p>
<p>Server: <?php echo $_SERVER['SERVER_SOFTWARE']; ?></p>
<p>Your IP: <?php echo $_SERVER['REMOTE_ADDR']; ?></p>
</div>
</body>
</html>
EOF
# Create virtual host config
sudo nano /etc/httpd/conf.d/site1.com.conf
<VirtualHost *:80>
ServerName site1.com
ServerAlias www.site1.com
DocumentRoot /var/www/site1.com/public_html
# Logs
ErrorLog /var/www/site1.com/logs/error.log
CustomLog /var/www/site1.com/logs/access.log combined
# Directory settings
<Directory /var/www/site1.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# PHP settings (if using PHP)
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php-fpm/www.sock|fcgi://localhost"
</FilesMatch>
# 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"
# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/javascript
</IfModule>
</VirtualHost>
Test Configuration
# Check syntax
sudo apachectl configtest
# Reload Apache
sudo systemctl reload httpd
# Test locally
curl -H "Host: site1.com" http://localhost
# Add to /etc/hosts for testing
echo "127.0.0.1 site1.com www.site1.com" | sudo tee -a /etc/hosts
๐ Step 3: SSL/TLS Configuration
Secure your sites with HTTPS!
Install Certbot
# Install Certbot for Let's Encrypt
sudo dnf install -y epel-release
sudo dnf install -y certbot python3-certbot-apache
# Get SSL certificate
sudo certbot --apache -d site1.com -d www.site1.com
# Or manually with standalone
sudo certbot certonly --standalone -d site1.com -d www.site1.com
Manual SSL Configuration
# Create SSL virtual host
sudo nano /etc/httpd/conf.d/site1.com-ssl.conf
<VirtualHost *:443>
ServerName site1.com
ServerAlias www.site1.com
DocumentRoot /var/www/site1.com/public_html
# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/site1.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/site1.com/privkey.pem
# Modern SSL settings
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder off
SSLSessionTickets off
# HSTS (optional but recommended)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# Logs
ErrorLog /var/www/site1.com/logs/ssl_error.log
CustomLog /var/www/site1.com/logs/ssl_access.log combined
<Directory /var/www/site1.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# Redirect HTTP to HTTPS
<VirtualHost *:80>
ServerName site1.com
ServerAlias www.site1.com
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
Auto-Renew Certificates
# Test renewal
sudo certbot renew --dry-run
# Add to crontab
sudo crontab -e
# Add:
0 0,12 * * * /usr/bin/certbot renew --quiet && systemctl reload httpd
โ Step 4: Performance Optimization
Make your Apache fly! ๐
Enable Caching
# Install caching module
sudo dnf install -y mod_cache
# Configure caching
sudo nano /etc/httpd/conf.d/cache.conf
# Memory cache
<IfModule mod_cache.c>
CacheEnable mem /
MCacheSize 4096
MCacheMaxObjectCount 1000
MCacheMinObjectSize 1
MCacheMaxObjectSize 2048
# Disk cache
CacheEnable disk /
CacheRoot /var/cache/httpd/proxy
CacheDirLevels 2
CacheDirLength 1
CacheMaxFileSize 1000000
# Cache static files
<FilesMatch "\.(jpg|jpeg|png|gif|css|js|ico)$">
Header set Cache-Control "max-age=604800, public"
</FilesMatch>
</IfModule>
# Browser caching with .htaccess
cat > /var/www/site1.com/public_html/.htaccess << 'EOF'
# Enable compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/javascript
</IfModule>
# Browser caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "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>
EOF
Enable HTTP/2
# Enable HTTP/2 module
sudo nano /etc/httpd/conf.modules.d/00-mpm.conf
# Comment out prefork, enable event
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
LoadModule mpm_event_module modules/mod_mpm_event.so
# Enable HTTP/2
sudo nano /etc/httpd/conf.d/ssl.conf
# Add:
Protocols h2 h2c http/1.1
# Restart Apache
sudo systemctl restart httpd
๐ฎ Quick Examples
Example 1: WordPress Hosting Setup ๐
#!/bin/bash
# Automated WordPress setup
setup_wordpress() {
DOMAIN=$1
DB_NAME=$(echo $DOMAIN | tr . _)
DB_USER=$DB_NAME
DB_PASS=$(openssl rand -base64 12)
echo "๐ Setting up WordPress for $DOMAIN"
# Create directory structure
sudo mkdir -p /var/www/$DOMAIN/{public_html,logs,ssl}
# Download WordPress
cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo cp -R wordpress/* /var/www/$DOMAIN/public_html/
# Create database
mysql -u root << EOF
CREATE DATABASE $DB_NAME;
CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASS';
GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
EOF
# Configure WordPress
cd /var/www/$DOMAIN/public_html
sudo cp wp-config-sample.php wp-config.php
sudo sed -i "s/database_name_here/$DB_NAME/" wp-config.php
sudo sed -i "s/username_here/$DB_USER/" wp-config.php
sudo sed -i "s/password_here/$DB_PASS/" wp-config.php
# Add salts
SALTS=$(curl -s https://api.wordpress.org/secret-key/1.1/salt/)
sudo sed -i "/AUTH_KEY/d" wp-config.php
sudo sed -i "/SECURE_AUTH_KEY/d" wp-config.php
sudo sed -i "/LOGGED_IN_KEY/d" wp-config.php
sudo sed -i "/NONCE_KEY/d" wp-config.php
echo "$SALTS" | sudo tee -a wp-config.php
# Set permissions
sudo chown -R apache:apache /var/www/$DOMAIN
sudo find /var/www/$DOMAIN -type d -exec chmod 755 {} \;
sudo find /var/www/$DOMAIN -type f -exec chmod 644 {} \;
# Create Apache config
cat << VHOST | sudo tee /etc/httpd/conf.d/$DOMAIN.conf
<VirtualHost *:80>
ServerName $DOMAIN
ServerAlias www.$DOMAIN
DocumentRoot /var/www/$DOMAIN/public_html
ErrorLog /var/www/$DOMAIN/logs/error.log
CustomLog /var/www/$DOMAIN/logs/access.log combined
<Directory /var/www/$DOMAIN/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# PHP-FPM
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php-fpm/www.sock|fcgi://localhost"
</FilesMatch>
</VirtualHost>
VHOST
# Get SSL certificate
sudo certbot --apache -d $DOMAIN -d www.$DOMAIN --non-interactive --agree-tos -m admin@$DOMAIN
# Reload Apache
sudo systemctl reload httpd
echo "โ
WordPress installed!"
echo "๐ URL: https://$DOMAIN"
echo "๐ Database: $DB_NAME"
echo "๐ DB Password: $DB_PASS"
echo "๐ Complete setup at https://$DOMAIN/wp-admin/install.php"
}
# Install WordPress for multiple sites
setup_wordpress "blog.example.com"
setup_wordpress "shop.example.com"
Example 2: Load Balancer Configuration โ๏ธ
#!/bin/bash
# Set up Apache as load balancer
configure_load_balancer() {
echo "โ๏ธ Configuring Apache Load Balancer"
# Enable proxy modules
sudo dnf install -y mod_proxy_html
# Create load balancer config
cat << 'EOF' | sudo tee /etc/httpd/conf.d/loadbalancer.conf
<VirtualHost *:80>
ServerName lb.example.com
# Enable proxy
ProxyRequests Off
ProxyPreserveHost On
# Load balancing with sticky sessions
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy "balancer://mycluster">
BalancerMember http://192.168.1.101:80 route=server1
BalancerMember http://192.168.1.102:80 route=server2
BalancerMember http://192.168.1.103:80 route=server3
ProxySet stickysession=ROUTEID
ProxySet lbmethod=byrequests
</Proxy>
# Health check
<Location "/balancer-manager">
SetHandler balancer-manager
Require host localhost
</Location>
ProxyPass /balancer-manager !
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
# Logging
ErrorLog logs/lb_error.log
CustomLog logs/lb_access.log combined
</VirtualHost>
# With health checks
<VirtualHost *:443>
ServerName lb.example.com
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/server.crt
SSLCertificateKeyFile /etc/pki/tls/private/server.key
<Proxy "balancer://securecluster">
BalancerMember https://192.168.1.101:443 route=server1 hcmethod=GET hcuri=/health
BalancerMember https://192.168.1.102:443 route=server2 hcmethod=GET hcuri=/health
BalancerMember https://192.168.1.103:443 route=server3 hcmethod=GET hcuri=/health
ProxySet stickysession=ROUTEID
ProxySet lbmethod=bytraffic
</Proxy>
ProxyPass / balancer://securecluster/
ProxyPassReverse / balancer://securecluster/
</VirtualHost>
EOF
sudo systemctl reload httpd
echo "โ
Load balancer configured!"
}
configure_load_balancer
Example 3: Security Hardening Script ๐
#!/bin/bash
# Harden Apache security
harden_apache() {
echo "๐ Hardening Apache Security"
# Install mod_security
sudo dnf install -y mod_security mod_security_crs
# Configure mod_security
cat << 'EOF' | sudo tee /etc/httpd/conf.d/mod_security.conf
<IfModule mod_security2.c>
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess Off
SecRequestBodyLimit 13107200
SecRequestBodyInMemoryLimit 131072
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogType Serial
SecAuditLog /var/log/httpd/modsec_audit.log
# Include OWASP rules
Include /usr/share/mod_modsecurity_crs/activated_rules/*.conf
</IfModule>
EOF
# Configure mod_evasive (DDoS protection)
cat << 'EOF' | sudo tee /etc/httpd/conf.d/mod_evasive.conf
<IfModule mod_evasive24.c>
DOSHashTableSize 3097
DOSPageCount 2
DOSSiteCount 50
DOSPageInterval 1
DOSSiteInterval 1
DOSBlockingPeriod 10
DOSEmailNotify [email protected]
DOSLogDir /var/log/httpd/mod_evasive
</IfModule>
EOF
# Create log directory
sudo mkdir -p /var/log/httpd/mod_evasive
sudo chown apache:apache /var/log/httpd/mod_evasive
# Disable dangerous modules
sudo sed -i 's/LoadModule autoindex_module/#LoadModule autoindex_module/' /etc/httpd/conf.modules.d/00-base.conf
sudo sed -i 's/LoadModule status_module/#LoadModule status_module/' /etc/httpd/conf.modules.d/00-base.conf
# Security headers
cat << 'EOF' | sudo tee -a /etc/httpd/conf/httpd.conf
# 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"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self';"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
# Hide Apache version
ServerTokens Prod
ServerSignature Off
# Disable TRACE
TraceEnable off
# Prevent clickjacking
Header always append X-Frame-Options DENY
# File upload limits
LimitRequestBody 10485760
EOF
# Restart Apache
sudo systemctl restart httpd
echo "โ
Apache hardened!"
}
harden_apache
๐จ Fix Common Problems
Problem 1: 403 Forbidden Error โ
Canโt access your site?
# Check permissions
ls -la /var/www/site1.com/
# Fix ownership
sudo chown -R apache:apache /var/www/site1.com
# Fix SELinux context
sudo restorecon -Rv /var/www/
# Set SELinux boolean
sudo setsebool -P httpd_can_network_connect 1
sudo setsebool -P httpd_read_user_content 1
Problem 2: Apache Wonโt Start โ
Service fails to start?
# Check for errors
sudo journalctl -xe | grep httpd
# Test configuration
sudo apachectl configtest
# Check port conflicts
sudo ss -tulpn | grep :80
# Common fix: Another service using port 80
sudo systemctl stop nginx
Problem 3: SSL Not Working โ
HTTPS showing errors?
# Check certificate
openssl x509 -in /path/to/cert.pem -text -noout
# Test SSL
openssl s_client -connect site1.com:443
# Fix certificate permissions
sudo chmod 600 /etc/pki/tls/private/*.key
# Renew certificate
sudo certbot renew --force-renewal
Problem 4: Slow Performance โ
Site loading slowly?
# Check Apache status
sudo systemctl status httpd
apachectl status
# Enable status module temporarily
sudo apachectl -M | grep status
# Tune MPM settings
sudo nano /etc/httpd/conf.modules.d/00-mpm.conf
# Monitor connections
watch -n 1 'ss -ant | grep :80 | wc -l'
# Check memory usage
free -h
ps aux | grep httpd | awk '{sum+=$6} END {print sum/1024 " MB"}'
๐ Simple Commands Summary
Task | Command |
---|---|
๐ Start Apache | sudo systemctl start httpd |
๐ Reload config | sudo systemctl reload httpd |
โ Test config | sudo apachectl configtest |
๐ Check status | sudo systemctl status httpd |
๐ List modules | httpd -M |
๐ List vhosts | apachectl -S |
๐ Error logs | sudo tail -f /var/log/httpd/error_log |
๐ Get SSL | sudo certbot --apache |
๐ก Tips for Success
- Test Locally First ๐งช - Use /etc/hosts before DNS
- Monitor Logs ๐ - tail -f is your friend
- Use .htaccess Wisely ๐ - Great power, use carefully
- Cache Everything ๐พ - Speed matters
- Automate Backups ๐ - Before itโs too late
- Document Configs ๐ - Future you will thank you
Funny story: I once spent 3 hours debugging a โbrokenโ site. Turns out I was editing the wrong virtual host file. Always double-check your domain names! ๐
๐ What You Learned
Youโre now a web hosting pro! You can:
- โ Install and configure Apache
- โ Set up virtual hosts
- โ Configure SSL/TLS certificates
- โ Optimize performance
- โ Implement security hardening
- โ Troubleshoot common issues
- โ Host multiple websites
๐ฏ Why This Matters
Running your own web server means:
- ๐ฐ Massive cost savings
- ๐ Complete control
- โก Better performance
- ๐ฏ Custom configurations
- ๐ Unlimited scalability
- ๐ช Professional skills
Last month, I migrated a client from managed hosting ($300/month) to their own Apache server ($20/month VPS). Same performance, 10% of the cost, plus they can host unlimited sites now. Thatโs the power of knowing Apache! ๐
Remember: Every major website started on a simple Apache server. Now you have the same tools! ๐
Happy hosting! May your sites be fast and your uptime 100%! ๐โจ