What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
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.
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.
#1 Best Overall
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.
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:
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.
Rank #2
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.
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.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →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:
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.
Rank #4
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.
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:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problems<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.
Best Value
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:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →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.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchMatch 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
httpdwithsudo dnf install httpd. - Allow TCP 80 in firewalld when the firewall is enabled, then reload it.
- Run
sudo systemctl enable --now httpdand verify an active service. - Create a test page in
/var/www/htmland verify it with localcurl. - 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_tSELinux context. - For custom roots, create a persistent
semanage fcontextrule and runrestorecon. - For custom ports, configure both firewalld and the SELinux
http_port_ttype. - Run
apachectl configtestbefore 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.
Quick Recap
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.
Recommended Free Tools




