How to Host a WordPress Site on Fedora

You can self-host a WordPress site on Fedora by installing Apache (or Nginx), MariaDB, and PHP through DNF, then configuring them to serve your site.

The scenario

You just provisioned a fresh Fedora Server instance or repurposed an old desktop machine. You want to run a WordPress blog, a small portfolio, or a local development environment. You install Apache, MariaDB, and PHP, drop the WordPress files into /var/www/html, and point your browser at the machine. The page loads a blank screen, or you get a 500 Internal Server Error, or the installation wizard refuses to connect to the database. The stack is installed, but the pieces are not talking to each other. This happens because Fedora ships with strict defaults. SELinux blocks web servers from writing to directories they should not touch. The firewall drops incoming HTTP traffic. PHP runs in a mode that expects explicit configuration. You need to align the services, adjust the security contexts, and verify the connections before the site will render.

What the LAMP stack actually does

LAMP stands for Linux, Apache, MariaDB, and PHP. Think of it as a restaurant kitchen. Apache is the front desk that takes orders from visitors. PHP is the chef that reads the recipe, prepares the ingredients, and plates the response. MariaDB is the walk-in freezer that stores the raw ingredients and keeps them organized. WordPress is the recipe book that tells the chef exactly what to cook for every page request. If the front desk cannot reach the kitchen, the order fails. If the chef cannot open the freezer, the meal never gets made. If the recipe book is missing or unreadable, the kitchen returns a blank plate. Your job is to make sure the doors are open, the permissions are correct, and the services are running in the right order.

Fedora has moved away from loading PHP directly into Apache. Older tutorials recommend mod_php, but that approach ties the web server and the scripting engine together. A crash in one takes down the other. Fedora uses php-fpm instead. Apache passes requests to a separate PHP process manager through a Unix socket. This isolation keeps the system stable under load and matches modern deployment practices. Trust the package manager defaults. Manual file edits drift, snapshots stay.

Install and configure the services

Fedora provides all four components in the default repositories. You do not need third-party repos or manual compilation. Run the installation command from a terminal with root privileges.

sudo dnf install -y httpd mariadb-server php php-mysqlnd php-fpm php-json php-xml php-gd # WHY: Installs Apache, MariaDB, and PHP with the extensions WordPress requires for database connectivity, JSON handling, XML parsing, and image processing

After the packages finish downloading, start the web server and the database, then enable them to survive reboots. Systemd tracks service dependencies automatically, so MariaDB will start before Apache if you enable them together.

sudo systemctl enable --now httpd mariadb # WHY: Starts both services immediately and registers them in systemd so they launch automatically after a reboot

Check the status of each service to confirm they are active. Systemd tracks the exit codes and recent log lines in one view. Always verify the state before moving to the next step.

sudo systemctl status httpd mariadb # WHY: Shows whether the services are running, their PID, and the last few journal entries for quick troubleshooting

Run journalctl -xe when a service fails to start. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type journalctl -xeu <unit> muscle-memory style. Read the actual error before guessing.

Set up the database

MariaDB ships with a root account that has no password by default. Leaving it open is a security risk. Run the security script to lock down the installation. The script will prompt you to set a root password, remove anonymous users, disable remote root login, and drop the test database. Answer Y to every prompt.

sudo mysql_secure_installation # WHY: Hardens the fresh MariaDB installation by enforcing authentication and removing default insecure accounts

WordPress needs its own database and a dedicated user account. Using the root account for application connections violates the principle of least privilege. Create a separate database, a user with a strong password, and grant that user full control over the new database only.

sudo mysql -u root -p <<'SQL'
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # WHY: Creates the database with full Unicode support for emojis and international characters
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'StrongPassword123!'; # WHY: Creates a restricted user that can only connect from the local machine
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost'; # WHY: Gives the user full control over the wordpress database without touching other databases
FLUSH PRIVILEGES; # WHY: Forces MariaDB to reload the grant tables so the new user takes effect immediately
SQL

Deploy WordPress files

Download the latest stable release directly from the official source. Extract the archive into the Apache document root, then move the contents into the root directory so the URL structure stays clean.

cd /var/www/html # WHY: Changes to the default Apache document root where web content is served
sudo curl -O https://wordpress.org/latest.tar.gz # WHY: Downloads the official WordPress archive to the current directory
sudo tar xzf latest.tar.gz # WHY: Extracts the compressed archive into a new wordpress subdirectory
sudo mv wordpress/* . # WHY: Moves all files and hidden directories into the document root to avoid /wordpress/ in the URL
sudo rm -rf wordpress latest.tar.gz # WHY: Cleans up the now-empty folder and the downloaded archive

WordPress needs a configuration file to connect to the database. Copy the sample file and edit it with your preferred editor. Replace the placeholder values with the database name, user, and password you created earlier.

sudo cp wp-config-sample.php wp-config.php # WHY: Creates a working configuration file from the provided template
sudo nano wp-config.php # WHY: Opens the file for editing so you can insert your database credentials

Locate the database constants near the top of the file. Update them to match your setup. Save the file and exit. Apache runs as the apache user on Fedora. The web server needs ownership of the files to read them, and it needs write access to the wp-content directory for uploads and plugin installations.

sudo chown -R apache:apache /var/www/html # WHY: Assigns ownership of all web files to the Apache user so the service can read and write them
sudo chmod -R 755 /var/www/html # WHY: Sets directories to rwxr-xr-x and files to rw-r--r-- for secure web serving

Config files in /etc/ are user-modified. Files in /usr/lib/ ship with the package. Edit /etc/. Never edit /usr/lib/. WordPress stores its configuration in the document root, which is fine for this setup, but keep that rule in mind for Apache and PHP tuning later.

Handle SELinux and the firewall

Fedora enforces SELinux in enforcing mode by default. SELinux labels every file and process with a security context. Apache is allowed to read web content, but it is blocked from writing to directories unless you explicitly label them. WordPress needs to write to wp-content for media uploads, theme updates, and plugin installations. Adjust the boolean and the file context to allow this behavior.

sudo setsebool -P httpd_unified 1 # WHY: Permanently allows Apache to run PHP scripts and access shared resources across different contexts
sudo semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/html(/.*)?' # WHY: Tells SELinux to treat the entire document root as writable web content
sudo restorecon -Rv /var/www/html # WHY: Applies the new SELinux context labels to all existing files and directories recursively

The firewall blocks incoming traffic on ports 80 and 443 until you open them. Add the HTTP and HTTPS services to the permanent zone configuration, then reload the runtime rules.

sudo firewall-cmd --permanent --add-service=http --add-service=https # WHY: Adds web traffic rules to the persistent firewall configuration
sudo firewall-cmd --reload # WHY: Applies the permanent rules to the active firewall without dropping existing connections

Run firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux.

Verify the installation

Point your browser at http://your-server-ip/. The WordPress installation wizard should load. If you see a blank page or a 500 Internal Server Error, the issue is almost always a permission mismatch or a missing PHP extension. Check the Apache error log first.

sudo journalctl -xeu httpd # WHY: Shows recent Apache logs with explanatory context to pinpoint missing modules or permission denials

Look for lines mentioning Permission denied or PHP Fatal error. If the wizard loads but fails to connect to the database, verify the MariaDB service is running and the credentials in wp-config.php match exactly. Test the connection from the command line to isolate the problem.

mysql -u wpuser -p -e "SELECT 1;" # WHY: Tests whether the WordPress user can authenticate and execute a basic query

Reboot before you debug. Half the time the symptom is gone.

Common pitfalls and error messages

The wp-config.php file will refuse to load and Apache will return Error: PHP Fatal error: Uncaught Error: Call to undefined function mysqli_connect(). The php-mysqlnd package is missing or not enabled. Run sudo dnf install php-mysqlnd and restart Apache.

If you see Warning: mysqli::mysqli(): (HY000/2002): No such file or directory in the logs, MariaDB is not running or the socket path is incorrect. Check the service status and ensure the database is listening on the default socket.

WordPress will print Error establishing a database connection on the front end when the credentials are wrong or the database service is down. Verify the username, password, and database name in wp-config.php. Run sudo systemctl status mariadb to confirm the service is active.

SELinux will block file uploads and return Warning: move_uploaded_file(): Unable to move in the PHP error log. The httpd_sys_rw_content_t context is missing or restorecon was not run. Reapply the context and verify with ls -Z /var/www/html/wp-content/.

Run journalctl first. Read the actual error before guessing.

When to use this stack versus alternatives

Use the LAMP stack when you need full control over server configuration, custom PHP extensions, or direct database access. Use Docker when you want isolated environments that you can destroy and recreate without touching the host system. Use a managed hosting provider when you do not want to handle security patches, backups, or SELinux policies. Use a static site generator when your content does not change frequently and you do not need a database backend. Stay on the upstream LAMP stack if you are learning system administration and want to understand how web servers, databases, and security modules interact.

Where to go next