You pointed the domain, but the site won't load
You pointed your domain to the server IP. You refreshed the browser. Instead of your homepage, you see the default Fedora test page, or a 403 Forbidden error. You installed httpd, you dropped your HTML files in a folder, and you expected the site to appear. Fedora does not guess. It enforces policy. The server is running, but it is refusing to serve your files because you have not defined the virtual host, or you have not convinced the security layer that the files are safe.
What is actually happening
Apache on Fedora reads configuration in a strict order. The main configuration file sets global defaults. The conf.d directory holds your overrides. When a request hits port 80, Apache matches the Host header to a VirtualHost block. If it finds a match, it checks the DocumentRoot. Then SELinux steps in. SELinux checks the file context. If the file is not labeled for web content, Apache gets blocked before it reads the bytes. Finally, the firewall checks if port 80 is open. Miss one step, and the site stays down.
Fedora uses httpd as the service name, not apache2. The package is httpd, the daemon is httpd, and the config lives in /etc/httpd/. This naming convention aligns with Red Hat Enterprise Linux. If you follow tutorials for Debian or Ubuntu, the paths and service names will be wrong.
The fix
You need to create a virtual host configuration, set the correct SELinux labels, open the firewall, and restart the service. Follow these steps in order.
Create the directory and configuration file
Apache includes all files ending in .conf inside /etc/httpd/conf.d/. The files are loaded in alphabetical order. Name your file to reflect the domain it serves.
Here is how to create the directory for your site and the configuration file that tells Apache where to find it.
sudo mkdir -p /var/www/html/example
# Create the directory structure for the site files.
# The -p flag creates parent directories if they do not exist.
# Using /var/www/html keeps files within the default web root.
sudo nano /etc/httpd/conf.d/example.com.conf
# Open the configuration file in the terminal editor.
# Files in conf.d are automatically included by the main config.
# The filename should match the domain for easy identification.
Paste the following configuration into the file. Adjust the domain and path to match your setup.
<VirtualHost *:80>
# Listen on all network interfaces on port 80.
# *:80 matches any IP address assigned to the server.
# This block handles unencrypted HTTP traffic.
ServerName example.com
# The primary domain this virtual host handles.
# Must match the DNS A record exactly.
# Apache uses this to route requests to the correct block.
ServerAlias www.example.com
# Catch requests for the www subdomain as well.
# Prevents the default site from serving www traffic.
# Add additional aliases if you have more subdomains.
DocumentRoot /var/www/html/example
# The directory where your HTML files live.
# Apache will look for index.html in this path.
# This path must exist and be readable by the apache user.
<Directory /var/www/html/example>
# Set access control rules for the document root.
# Apache 2.4 requires explicit permission directives.
# This block overrides global directory restrictions.
Require all granted
# Allow access to all clients by default.
# Without this line, Apache returns 403 Forbidden.
# This is the standard directive for public websites.
</Directory>
ErrorLog logs/example.com-error_log
# Write error messages to a dedicated log file.
# The path is relative to the ServerRoot directory.
# Separate logs make troubleshooting specific sites easier.
CustomLog logs/example.com-access_log common
# Record every request in the access log.
# The common format includes IP, user, time, and request.
# Review this log to verify traffic is reaching the site.
</VirtualHost>
Save the file and exit the editor. Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/.
Validate the configuration syntax
Apache will refuse to restart if the configuration contains syntax errors. Always test the config before reloading the service.
Here is how to check for syntax errors without disrupting running traffic.
sudo apachectl configtest
# Parse the configuration files and check for syntax errors.
# This command does not start or restart the server.
# It returns "Syntax OK" if the config is valid.
If the command returns an error, it will point to the line number and file. Fix the error and run the command again. Do not restart Apache until you see Syntax OK.
Configure SELinux contexts
Fedora ships with SELinux in enforcing mode by default. This is a feature, not a bug. When Apache tries to read a file, the kernel checks the file's security context. Web content must have the httpd_sys_content_t label. Files in /var/www get this label automatically. Files in /home or /opt do not.
If you serve from /var/www, you can skip this section. If you serve from a non-standard directory, you must apply the correct label.
Here is how to check the current SELinux context and apply the correct label for web content.
ls -Z /var/www/html/example
# List the directory contents with SELinux context information.
# The -Z flag shows the security label for each file.
# Look for httpd_sys_content_t in the output.
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/html/example(/.*)?"
# Add a permanent file context rule for the directory and all contents.
# The regex pattern matches the directory and any files inside.
# This rule survives filesystem relabeling and system reboots.
sudo restorecon -R /var/www/html/example
# Apply the new context rule immediately to existing files.
# The -R flag processes the directory recursively.
# Without this step, files keep their old labels until touched.
SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Disabling SELinux opens the server to privilege escalation attacks. Fix the label instead.
Open the firewall
The firewall blocks incoming traffic by default. You must allow HTTP traffic on port 80. If you plan to use HTTPS, you also need port 443.
Here is how to add the HTTP service to the firewall and apply the changes.
sudo firewall-cmd --permanent --add-service=http
# Add the http service to the permanent firewall configuration.
# The --permanent flag writes the rule to disk.
# The rule does not take effect until the firewall reloads.
sudo firewall-cmd --reload
# Reload the firewall to apply the permanent rules to runtime.
# This step is mandatory after every permanent rule change.
# Without reload, the runtime config and persistent config diverge.
Restart Apache
The service needs to restart to read the new configuration file. Use systemctl to manage the service.
Here is how to restart Apache and verify the service state.
sudo systemctl restart httpd
# Restart the Apache web server daemon.
# This stops the current process and starts a new one.
# The new process loads the updated configuration files.
sudo systemctl status httpd
# Check the current status of the httpd service.
# Look for "active (running)" in the output.
# The command also shows recent log lines for quick debugging.
Verify it worked
Run a local request to confirm the virtual host is serving your files.
Here is how to test the site from the command line.
curl -I http://example.com
# Send a HEAD request to the domain.
# The -I flag fetches only the response headers.
# A 200 OK status means the site is reachable and serving content.
If you see 200 OK, the site is working. If you see 403 Forbidden, check the SELinux labels and the Require all granted directive. If you see 404 Not Found, check the DocumentRoot path and ensure index.html exists.
Run journalctl -xeu httpd to read the logs. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style.
Common pitfalls and what the error looks like
403 Forbidden: The server found the file but refuses to show it. This is almost always SELinux or directory permissions. Check ls -Z on the file. Check ls -ld on the directory. The directory must be executable by others (chmod 755). The files must be readable by others (chmod 644).
404 Not Found: The server cannot find the file. Check the DocumentRoot path in the config. Ensure the path matches the filesystem exactly. Case sensitivity matters. index.html is not Index.html.
Syntax error on configtest: You have a typo in the Apache config. Check for missing closing tags like </VirtualHost> or </Directory>. Check for spaces instead of tabs if using .htaccess files. Apache is strict about whitespace in some directives.
SELinux denial in logs: You see Permission denied in the error log, but the file permissions look correct. This is SELinux blocking the access. Check journalctl -t setroubleshoot. The log will tell you exactly which context is missing. Apply the correct semanage rule.
Port already in use: Apache fails to start with Address already in use. Another process is listening on port 80. Run sudo ss -tlnp | grep :80 to find the culprit. It might be another web server or a proxy. Stop the conflicting service or change the Apache port.
Reboot before you debug. Half the time the symptom is gone.
When to use this vs alternatives
Use Apache when you need .htaccess support for per-directory configuration overrides. Use Apache when you are running legacy PHP applications that depend on mod_php or specific Apache modules. Use Nginx when you need to handle thousands of concurrent connections with minimal memory overhead. Use Caddy when you want automatic HTTPS provisioning without manual certificate management. Use a static file server when you are only serving HTML and CSS and do not need a full web server stack.
Trust the package manager. Manual file edits drift, snapshots stay.