Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk10 min

How to Install the Apache Web Server on CentOS Stream 9

A complete CentOS Stream 9 Apache guide: install the httpd RPM, open ports, start the service, publish a page, configure SELinux and virtual hosts, add HTTPS, and diagnose failures.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

On CentOS Stream 9, Apache is installed from the httpd RPM, opened through firewalld, and managed with systemctl. Run the commands below to install it, publish a test page, verify the service, and avoid the SELinux and virtual-host problems that commonly make a new site appear offline.

What this procedure covers

This guide targets CentOS Stream 9 and the compatible Red Hat Enterprise Linux 9 family. CentOS Linux 8 and earlier releases have different repository and lifecycle assumptions, so do not apply their package instructions blindly to Stream 9. You need a server with a working network connection, an account allowed to run sudo, and either console access or SSH access. If the server is hosted by a cloud provider, you may also need to allow the same port in that provider’s security-group or network-access rules.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

CentOS calls the Apache HTTP Server package httpd. After installation, its principal configuration directory is /etc/httpd, and its logs are stored in /var/log/httpd. The default web document directory is /var/www/html.

Install the httpd package

Refresh package metadata and install Apache

Open a terminal and run:

sudo dnf install httpd

dnf resolves the package and its dependencies from the repositories configured on the server. Review the transaction summary and type y when prompted. If dnf reports that no package is available, check that the system is actually running CentOS Stream 9, that repository definitions are enabled, and that DNS and outbound HTTPS access work. Do not download an unrelated binary package from an untrusted site simply to bypass a repository problem.

Confirm that the package is present

Before changing service settings, you can confirm the installed package with:

rpm -q httpd

The command should print the installed package name and version. The RPM creates the standard service unit and the /etc/httpd and /var/log/httpd layout used by the CentOS Stream 9 package.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Allow web traffic through firewalld

Open TCP port 80

A running Apache process can still be unreachable from another computer if the host firewall drops incoming connections. If firewalld is enabled, add a permanent HTTP rule and reload the active configuration:

sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --reload

The service-oriented equivalent is:

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

Use one method, not both; each creates an allowance for the same HTTP service. A permanent rule is written to the firewall configuration, while --reload makes it effective immediately without stopping the firewall daemon.

Check the active firewall rules

To inspect the zone currently associated with the network interface, run:

sudo firewall-cmd --get-active-zones

Then list that zone’s effective rules, substituting its name for public if necessary:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo firewall-cmd --zone=public --list-all

Look for either http in the services list or 80/tcp in the ports list. If the operating-system firewall is open but an outside client still cannot connect, investigate upstream routing, DNS, a cloud security-group rule, or a network access-control list rather than repeatedly changing Apache.

Enable Apache at boot and start it now

Use the one-command form

Enable the service for future boots and start it immediately:

sudo systemctl enable --now httpd
sudo systemctl status httpd

enable creates the boot-time relationship, while --now starts the service in the current session. A successful status shows active (running). Press q to leave the status view.

Use separate commands when diagnosing

The equivalent explicit sequence is:

sudo systemctl enable httpd
sudo systemctl start httpd

Separating the operations helps identify whether a failure occurs while creating the boot configuration or while starting Apache. You can check whether it is enabled independently:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
systemctl is-enabled httpd
systemctl is-active httpd

Expected output is enabled and active. If the start operation fails, do not keep retrying blindly; inspect the journal and run a configuration test as described later.

Publish and test a first page

Create content in the default document root

Write a minimal page to /var/www/html/index.html:

echo 'Apache is working' | sudo tee /var/www/html/index.html

The command uses sudo tee so that the file is written with administrative permission while the shell itself does not need to run as root. For a real site, replace this one-line file with your application or static HTML, but keep the document root and its labels consistent with the server configuration.

Test locally on the server

Request the page through the local HTTP listener:

curl http://127.0.0.1/

The response should contain Apache is working. A successful local request proves that Apache is listening and can read the default content; it does not prove that DNS, the host firewall, a cloud firewall, or an external route is correct.

Test from another machine

Find the server’s reachable address and browse to http://server_IP_or_host_name/ from a different computer. If the browser shows the page locally but times out remotely, work through the network checks in the troubleshooting section. If the document root is empty, the Red Hat Enterprise Linux documentation notes that the server can display its default test page instead.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Understand Apache’s CentOS file layout

Path Purpose What to change carefully
/etc/httpd Main Apache configuration tree Virtual hosts, modules, listeners, and global directives
/var/www/html Default document root Static files or the initial test page
/var/log/httpd Apache access and error logs Use logs for diagnosis; do not delete active files casually

Keep configuration edits deliberate and test them before every restart. A syntax error in one included file can prevent the entire service from starting, even when the change concerns only one website.

Permissions and SELinux: the two checks behind many 403 errors

Make content readable

Every file and directory below the document root must be traversable and readable by the account under which httpd runs. A file that your interactive user can read is not necessarily readable by the service account. Check directory permissions through the complete path, and avoid making the entire tree world-writable as a shortcut. Keep private application files outside the publicly served directory.

Use the default SELinux context under /var/www

Content placed below /var/www receives the httpd_sys_content_t SELinux context by default. This label tells SELinux that the web service may read the files. If a file was copied from another location and retains an unrelated label, Apache can return HTTP 403 even when Unix ownership and mode bits look correct.

Inspect labels with:

ls -Z /var/www/html

When labels have drifted, restore the defaults for the tree:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo restorecon -Rv /var/www/html

Serve a document root outside /var/www

Custom layouts are supported, but SELinux needs a persistent file-context rule. The following example labels /srv/example.com and everything below it as web-readable:

sudo semanage fcontext -a -t httpd_sys_content_t '/srv/example.com(/.*)?'
sudo restorecon -Rv /srv/example.com/

The semanage utility is supplied by the policycoreutils-python-utils package on systems where it is not already installed. Install that package with sudo dnf install policycoreutils-python-utils if the command is missing, then repeat the labeling commands. The -a rule is persistent, so a later relabel operation will preserve the intended context.

Distinguish a file denial from a network denial

An HTTP 403 response means the request reached Apache but access was refused. Check path permissions, the SELinux label, and the Apache error log. A timeout or connection-refused message is a network or listener problem instead. Keeping these symptoms separate prevents unnecessary SELinux changes when the real issue is a closed firewall port.

Use a nonstandard HTTP port

Some applications require Apache to listen on a port other than 80. Two independent controls must allow that port: the host firewall and SELinux. For example, CentOS guidance uses TCP port 3131 as an additional HTTP port.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Assign the SELinux HTTP port type

sudo semanage port -a -t http_port_t -p tcp 3131

The http_port_t type covers standard HTTP ports such as 80 and 443 and must be assigned to an additional port before Apache can bind to it under enforcing SELinux. If the port has already been defined, semanage port -m modifies the existing entry instead of adding a duplicate.

Open the same port in firewalld

sudo firewall-cmd --permanent --add-port=3131/tcp
sudo firewall-cmd --reload

Configure Apache’s Listen directive and the relevant virtual host for port 3131, run apachectl configtest, and restart only after the syntax check succeeds. A firewall rule without the SELinux port label still leaves the service unable to bind; the label without the firewall rule still leaves remote clients blocked.

Host more than one domain with virtual hosts

When a single document root is enough

A basic installation serves the same content for every hostname that reaches the server. This is suitable for one site, a temporary landing page, or a server whose routing is handled elsewhere. It does not provide separate content, logs, or policy for multiple domains.

Create a name-based virtual host for each site

For multiple domains, define a separate name-based <VirtualHost> block for each site. Each block should specify its own ServerName, DocumentRoot, CustomLog, and ErrorLog. A conceptual example is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /srv/example.com
    CustomLog /var/log/httpd/example.com_access.log combined
    ErrorLog /var/log/httpd/example.com_error.log
</VirtualHost>

Create the directory and an index file, ensure the service can traverse and read the path, and apply the persistent SELinux labeling procedure shown above. Add DNS records that point each hostname to the server’s address. The ServerName value must match the hostname sent by the client; otherwise Apache may select a different virtual host.

Validate before exposing the site

Run:

sudo apachectl configtest

Proceed only when the output is Syntax OK. Then reload or restart Apache and test each hostname with curl or a browser. Separate access and error logs make it possible to tell which virtual host handled a request and which one generated an error.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Add HTTPS on port 443

Install the TLS module

Install the Apache SSL module package:

sudo dnf install mod_ssl

Configure a TLS virtual host with the certificate and key directives SSLCertificateFile and SSLCertificateKeyFile. When your certificate chain requires a separate CA bundle, configure SSLCACertificateFile as applicable.

Protect the private key

Keep the private key readable only by root and set its mode to 600:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo chmod 600 /path/to/private-key.pem

Use the actual path supplied by your certificate deployment. Do not place private keys in the public document root or embed them in application files.

Open HTTPS and restart safely

sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
sudo apachectl configtest
sudo systemctl restart httpd

Port 443 must be permitted in firewalld as well as any upstream security group. A certificate-path error, unreadable key, or malformed directive will appear in the configuration-test output or the system journal; fix it before attempting another restart.

Verify configuration and diagnose failures

Check syntax before every restart

Use either command:

sudo apachectl configtest
sudo httpd -t

The expected result is Syntax OK. This check parses the configuration without replacing the currently running process, making it safer than discovering a typo during a production restart.

Read the service journal

sudo systemctl status httpd
sudo journalctl -u httpd

The journal identifies failed binds, missing files, permission errors, and module-loading problems. For request-level details, inspect files in /var/log/httpd, especially the error log associated with the affected virtual host.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Match the symptom to the likely cause

Symptom Likely area First checks
Local curl fails Service or configuration systemctl status httpd, apachectl configtest, and journalctl -u httpd
Local request works; remote connection times out Firewall, route, DNS, or cloud security group firewalld zone, port rule, server address, upstream network policy
HTTP 403 File permissions or SELinux Path readability, ls -Z, restorecon, and Apache error log
Apache cannot bind to a custom port SELinux port policy or another listener semanage port -l, ss -ltnp, and the configured Listen value
Wrong site’s page appears Virtual-host matching or DNS ServerName, DNS records, and each virtual host’s document root

Do not disable SELinux as a shortcut

If a denial appears, correct the file context, port type, or policy requirement that caused it. Disabling enforcing mode hides the configuration error and removes a major protection layer. The persistent semanage fcontext and semanage port rules solve the common Apache cases without changing the system’s overall security mode.

Choose an installation and layout that fits the server

Decision Default choice When to choose the alternative
Operating system CentOS Stream 9 Use another RHEL-family release only when its lifecycle, repositories, and support requirements are explicitly aligned with your environment.
Installation method Repository-provided httpd RPM Build from source only when you have a documented need for a version or compile-time option unavailable in the supported repositories; you then own more update and service-integration work.
Content layout /var/www/html Use a custom path such as /srv/example.com for isolation or an existing filesystem, and add persistent SELinux labeling.
Site model One shared document root Use name-based virtual hosts when domains need separate content, logs, or configuration.
Transport HTTP on TCP 80 for initial testing Configure TLS on TCP 443 for a production site, with protected private keys and valid certificate directives.

The repository RPM is normally the least-surprising choice on Stream 9 because it integrates with dnf, the packaged systemd unit, the CentOS directory layout, and the operating system’s SELinux policy. A source build can be appropriate for specialist requirements, but it changes paths, update procedures, and troubleshooting assumptions; document those differences before deploying it.

Post-install checklist

  • Confirm the host is CentOS Stream 9 or a compatible RHEL 9 system.
  • Install httpd with sudo dnf install httpd.
  • Allow TCP 80 in firewalld when the firewall is enabled, then reload it.
  • Run sudo systemctl enable --now httpd and verify an active service.
  • Create a test page in /var/www/html and verify it with local curl.
  • Test from another machine only after checking host and upstream firewall rules.
  • Keep web files readable by the service account and preserve the httpd_sys_content_t SELinux context.
  • For custom roots, create a persistent semanage fcontext rule and run restorecon.
  • For custom ports, configure both firewalld and the SELinux http_port_t type.
  • Run apachectl configtest before every restart or reload.
  • For multiple domains, give each virtual host its own name, root, and logs.
  • For HTTPS, install mod_ssl, configure certificate directives, protect the key with mode 600, and open port 443.

What a successful result looks like

The service is enabled and active, curl http://127.0.0.1/ returns your page, and an external browser reaches the same content through the server’s hostname or address. Apache’s configuration test reports Syntax OK; the document root has the expected SELinux label; and the firewall exposes only the ports you intentionally configured. With those checks complete, you have a sound CentOS Stream 9 foundation for static files, name-based virtual hosts, or a TLS-enabled site.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.