...
How to setup apache virtual hosts on ubuntu vps
Discover how to setup apache virtual hosts on ubuntu vps!

This article provides a guide demonstrating how to setup Apache virtual hosts on Ubuntu VPS.

This guide walks you through creating multiple websites (virtual hosts) on a single Ubuntu VPS server using Apache. It covers HTTP, optional HTTPS with Let’s Encrypt, and common gotchas (and workarounds to resolve).

Before we learn how to setup Apache virtual hosts on Ubuntu VPS, let’s take a brief moment to understand Apache virtual hosts.

What are Apache Virtual Hosts?

Apache Virtual Hosts (often called vhosts) are a feature of the Apache HTTP Server that allow you to run multiple websites on a single server. Instead of needing a separate server (or IP address) for each site, you can configure Apache to β€œhost” multiple domains and applications from one machine.

πŸ”‘ Key Concepts

  1. Domain-based (Name-based) Virtual Hosts
    • Most common type.
    • Multiple domains (e.g., example.com, mysite.com) share the same IP address.
    • Apache decides which website to serve based on the Host header sent by the browser.
  2. Add PostIP-based Virtual Hosts
    • Each site has a unique IP address.
    • Less common now (since IPv4 addresses are limited), but sometimes used for legacy apps or SSL setups before SNI (Server Name Indication).
  3. Port-based Virtual Hosts
    • Different sites run on different ports of the same server (e.g., example.com:8080 vs example.com:9090).
    • Usually used for internal services rather than public websites.

βš™οΈ How They Work

When a request comes in:

  1. The browser sends the domain name in the HTTP request (Host header).
  2. Apache matches it with the ServerName or ServerAlias in the virtual host configuration.
  3. Apache serves the site from the specified DocumentRoot (the folder containing the website’s files).

πŸš€ Benefits

  • Host multiple domains/websites on a single server.
  • Isolate websites into different directories.
  • Configure separate logs, security rules, and SSL certificates per site.
  • Reduce infrastructure costs by consolidating hosting.

Prerequisites

This guide assumes the following environmental prerequisites are met:

Launch 100% ssd ubuntu vps from $2. 49/mo!

How to Setup Apache Virtual Hosts on Ubuntu VPS (Noble Numbat) πŸ§πŸ› οΈ

To setup Apache virtual hosts on Ubuntu VPS, follow the steps outlined below:

Replace example.com everywhere with your actual domain.

  1. Install & Verify Apache πŸ”§

    sudo apt update
    sudo apt install -y apache2
    apache2ctl -v        # Should show Apache/2.4.x
    

    Enable on boot and start:

    sudo systemctl enable --now apache2
    sudo systemctl status apache2
    

    Open the firewall (if UFW is enabled):

    sudo ufw allow 'Apache'
    sudo ufw status
    
  2. Create a Document Root Per Site πŸ—‚οΈ

    We’ll keep code under /var/www//public_html.

    sudo mkdir -p /var/www/example.com/public_html
    sudo chown -R $USER:www-data /var/www/example.com
    sudo chmod -R 750 /var/www/example.com
    

    Drop in a quick test page:

    cat <<'HTML' > /var/www/example.com/public_html/index.html
    <!doctype html>
    <html><head><meta charset="utf-8"><title>example.com</title></head>
    <body><h1>Hello from example.com πŸŽ‰</h1></body></html>
    HTML
    

    (Repeat these steps for each site you host, e.g., secondsite.com.)

  3. Create a Virtual Host File πŸ“

    Apache keeps site configs in /etc/apache2/sites-available/. Create one per domain:

    sudo nano /etc/apache2/sites-available/example.com.conf
    

    Paste this minimal, production-friendly vhost for HTTP (port 80):

    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        DocumentRoot /var/www/example.com/public_html
    
        <Directory /var/www/example.com/public_html>
            Options -Indexes +FollowSymLinks
            AllowOverride None
            Require all granted
        </Directory>
    
        ErrorLog  ${APACHE_LOG_DIR}/example.com_error.log
        CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
    
        # Optional: If you later enable HTTP/2 globally
        #Protocols h3 h3c http/1.1
    </VirtualHost>

    If you rely on .htaccess (e.g., for WordPress), set AllowOverride All instead of None and enable mod_rewrite (next step).

  4. Enable Site & Common Modules βœ…

    # Enable the site
    sudo a2ensite example.com.conf
    
    # (Optional) If you’ll use .htaccess or redirects/rewrite rules
    sudo a2enmod rewrite
    
    # (Optional) Security and caching helpers you’ll likely want
    sudo a2enmod headers expires
    
    # Disable the default site to avoid collisions (optional but recommended)
    sudo a2dissite 000-default.conf
    
    # Check syntax and reload
    sudo apache2ctl configtest
    sudo systemctl reload apache2
    

    Test:

    curl -I http://example.com
    

    If DNS isn’t pointed yet, you can temporarily test from your own computer by adding this line to /etc/hosts (Linux/macOS) or C:\Windows\System32\drivers\etc\hosts (Windows):

    YOUR_SERVER_IP  example.com  www.example.com
    
  5. Point DNS to Your Server 🌐

    At your DNS provider, create A (and optional AAAA) records (full guide: How to Point a Domain to Your VPS Server):

    • example.com β†’ YOUR_SERVER_IP
    • www.example.com β†’ YOUR_SERVER_IP

    DNS propagation can take time. You can check with:

    dig +short A example.com
    
  6. (Optional but recommended) Add HTTPS with Let’s Encrypt πŸ”’

    On Ubuntu 24.04, the recommended method is snap:

    sudo snap install core
    sudo snap refresh core
    sudo snap install --classic certbot
    sudo ln -sf /snap/bin/certbot /usr/bin/certbot
    

    Request and auto-configure SSL for Apache:

    sudo certbot --apache -d example.com -d www.example.com
    
    • Choose the redirect option so HTTP goes to HTTPS.
    • Certbot sets up automatic renewal. Verify with:
      sudo systemctl status snap.certbot.renew.service
      sudo certbot renew --dry-run
    

    Open full HTTPS in UFW:

    sudo ufw allow 'Apache Full'
    sudo ufw delete allow 'Apache'  # optional cleanup
    
  7. Useful Quality-of-Life Tweaks 🧰

    Avoid the β€œcould not reliably determine the server’s fully qualified domain name” warning:

    echo "ServerName $(hostname -f)" | sudo tee /etc/apache2/conf-available/servername.conf
    sudo a2enconf servername
    sudo systemctl reload apache2
    

    Per-site .htaccess (if truly needed):

    <Directory /var/www/example.com/public_html>
        AllowOverride All
        Require all granted
    </Directory>
    

    Then:

    sudo a2enmod rewrite
    sudo systemctl reload apache2
    

    Force non-www (in your HTTPS vhost) via rewrite rules:

    <VirtualHost *:443>
        # ... your SSL directives ...
        ServerName example.com
        ServerAlias www.example.com
    
        RewriteEngine On
        RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
        RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
    </VirtualHost>
    
  8. Add Another Site (Quick Template) 🧩

    Use your first config as a template:

    # Document root
    sudo mkdir -p /var/www/secondsite.com/public_html
    sudo chown -R $USER:www-data /var/www/secondsite.com
    sudo chmod -R 750 /var/www/secondsite.com
    
    # Vhost
    sudo cp /etc/apache2/sites-available/example.com.conf /etc/apache2/sites-available/secondsite.com.conf
    sudo nano /etc/apache2/sites-available/secondsite.com.conf
    # -> Change all example.com to secondsite.com and update paths
    
    # Enable & reload
    sudo a2ensite secondsite.com.conf
    sudo apache2ctl configtest
    sudo systemctl reload apache2
    

    Get an SSL cert:

    sudo certbot --apache -d secondsite.com -d www.secondsite.com
    
  9. Troubleshooting πŸ§ͺ

    • Syntax errors:
      apache2ctl configtest shows where; fix and systemctl reload apache2.
    • Wrong site served:
      Ensure the correct vhost file is enabled, has the right ServerName/ServerAlias, and the default site is disabled. List enabled sites with:

        a2query -s
      
    • Permissions/403:
      Confirm Apache can read the doc root:

      sudo -u www-data test -r /var/www/example.com/public_html/index.html && echo OK
      

      Adjust chown/chmod as needed.

    • DNS not pointing yet:
      Use /etc/hosts for temporary local testing (see Step 4).
  10. Housekeeping & Logs 🧹

    Logs live at:

    /var/log/apache2/*_access.log
    /var/log/apache2/*_error.log
    

    Follow a log live:

    sudo tail -f /var/log/apache2/example.com_error.log
    

    Reload Apache after any config change:

    sudo systemctl reload apache2
    

Virtual Host Templates

Here are some pre-made virtual host templates for common softwares:

  • WordPress

    # ── HTTP β†’ HTTPS redirect
    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        RewriteEngine On
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    
        # Fallback docroot (unused except ACME pre-SSL)
        DocumentRoot /var/www/example.com/public_html
    </VirtualHost>
    
    # ── HTTPS vhost
    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        DocumentRoot /var/www/example.com/public_html
    
        <Directory /var/www/example.com/public_html>
            Options -Indexes +FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>
    
        # HTTP/2
        Protocols h2 http/1.1
    
        # Logging
        ErrorLog  ${APACHE_LOG_DIR}/example.com_error.log
        CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
    
        # Security headers
        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        Header always set X-Content-Type-Options "nosniff"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
        # TLS (Let’s Encrypt)
        SSLEngine on
        SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem
    
        # Modern TLS hardening
        SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
        SSLCipherSuite          TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:EECDH+AESGCM:EDH+AESGCM
        SSLHonorCipherOrder     off
        SSLCompression          off
    
        # OCSP stapling
        SSLUseStapling          on
        SSLStaplingCache        "shmcb:/var/run/apache2/stapling_cache(128000)"
    </VirtualHost>
  • Laravel (PHP-FPM)

    # ── HTTP β†’ HTTPS redirect
    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        RewriteEngine On
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    
        DocumentRoot /var/www/example.com/public
    </VirtualHost>
    
    # ── HTTPS vhost (php8.3-fpm)
    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        DocumentRoot /var/www/example.com/public
    
        <Directory /var/www/example.com/public>
            Options +FollowSymLinks -Indexes
            AllowOverride All
            Require all granted
        </Directory>
    
        # Route PHP to FPM
        <FilesMatch \.php$>
            SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
        </FilesMatch>
    
        # Deny direct access to sensitive dirs (optional hardening)
        <Directory /var/www/example.com/storage>
            Require all denied
        </Directory>
        <Directory /var/www/example.com/bootstrap>
            Require all denied
        </Directory>
    
        Protocols h2 http/1.1
    
        ErrorLog  ${APACHE_LOG_DIR}/example.com_error.log
        CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
    
        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        Header always set X-Content-Type-Options "nosniff"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
        SSLEngine on
        SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem
    
        SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
        SSLCipherSuite          TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:EECDH+AESGCM:EDH+AESGCM
        SSLHonorCipherOrder     off
        SSLCompression          off
    
        SSLUseStapling          on
        SSLStaplingCache        "shmcb:/var/run/apache2/stapling_cache(128000)"
    </VirtualHost>
  • OpenCart

    # ── HTTP β†’ HTTPS redirect
    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        RewriteEngine On
        RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    
        DocumentRoot /var/www/example.com/public_html
    </VirtualHost>
    
    # ── HTTPS vhost
    <VirtualHost *:443>
        ServerName example.com
        ServerAlias www.example.com
        ServerAdmin webmaster@example.com
    
        DocumentRoot /var/www/example.com/public_html
    
        <Directory /var/www/example.com/public_html>
            Options -Indexes +FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>
    
        # Protect storage (move outside webroot if possible)
        <Directory /var/www/example.com/public_html/system/storage>
            Require all denied
        </Directory>
    
        Protocols h2 http/1.1
    
        ErrorLog  ${APACHE_LOG_DIR}/example.com_error.log
        CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined
    
        Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        Header always set X-Content-Type-Options "nosniff"
        Header always set Referrer-Policy "strict-origin-when-cross-origin"
    
        SSLEngine on
        SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
        SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem
    
        SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
        SSLCipherSuite          TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:EECDH+AESGCM:EDH+AESGCM
        SSLHonorCipherOrder     off
        SSLCompression          off
    
        SSLUseStapling          on
        SSLStaplingCache        "shmcb:/var/run/apache2/stapling_cache(128000)"
    </VirtualHost>

Enable modules & firewall (one-time) 🧰

sudo a2enmod ssl headers http2 rewrite socache_shmcb
# For Laravel only:
sudo a2enmod proxy_fcgi setenvif

sudo systemctl reload apache2

# UFW
sudo ufw allow 'Apache Full'
sudo ufw delete allow 'Apache'  # optional cleanup

Issue certificates with Certbot πŸ”‘

sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/bin/certbot

# Obtain & auto-configure (runs Apache plugin to verify)
sudo certbot --apache -d example.com -d www.example.com

# Verify auto-renewal
sudo certbot renew --dry-run

πŸ’‘ Certbot will keep /etc/letsencrypt/live/example.com/ symlinks up-to-date and renew automatically.

Quick checklist βœ…

  • DNS A/AAAA records point to the server 🌐
  • Files live in the correct docroots (public_html or public) πŸ“
  • Required Apache modules enabled (above) 🧩
  • Site enabled & config passes syntax:
sudo a2ensite example.com.conf
  sudo apache2ctl configtest && sudo systemctl reload apache2

You’re done! πŸš€

You now have clean, isolated virtual hosts on Ubuntu 24.04β€”easy to manage, secure with TLS, and ready to scale with more sites.
Launch 100% ssd ubuntu vps from $2. 49/mo!

Conclusion

You now know how to setup Apache virtual hosts on Ubuntu VPS!

Avatar of editorial staff

Editorial Staff

Rad Web Hosting is a leading provider of web hosting, Cloud VPS, and Dedicated Servers in Dallas, TX.
lg