
Setting up a web server on Fedora always feels a little different than doing the same job on Ubuntu or CentOS. The package manager behaves differently, SELinux is enforcing by default out of the box, and Fedora’s rapid release cycle means the versions of Apache, MariaDB, and PHP you get are almost always newer than what ships with the “stable” enterprise distros. That’s a blessing and a curse depending on which side of a 3 a.m. production incident you’re standing on.
If you’ve landed here because you’re trying to spin up a LAMP stack (Linux, Apache, MariaDB, PHP) on a fresh Fedora 44 install, you’re in the right place. Fedora 44, released in late April 2026, ships with DNF5 as the default package manager, updated SELinux policies, and current stable branches of Apache HTTP Server, MariaDB, and PHP straight from the official repositories. Most tutorials online still reference Fedora 34 or 36, and half the commands either fail outright or trigger permission errors nobody bothers explaining.
This guide walks through the entire process the way an actual sysadmin would do it on a real server: installing each component, verifying it’s actually running (not just “installed”), configuring the firewall properly instead of disabling it out of laziness, dealing with SELinux instead of setting it to permissive, and hardening the stack enough that you wouldn’t be embarrassed if someone audited it. Along the way, there are notes on what typically breaks, why it breaks, and how to fix it without guessing.
Whether you’re deploying WordPress, a Laravel app, a custom PHP CMS, or just testing something locally before pushing to production, the fundamentals here apply. Let’s get into it.
Why Fedora for a LAMP Stack in the First Place?
Before diving into commands, it’s worth addressing the obvious question: why would anyone run production infrastructure on Fedora instead of a longer-support distro like Ubuntu LTS, AlmaLinux, or Debian?
Honestly, most people shouldn’t for a customer-facing production box, at least not without a plan. Fedora has a short support window, roughly 13 months per release, and that means you’re committing to more frequent major upgrades than you would with Ubuntu LTS’s five-year cycle. That said, Fedora shines in a few scenarios: local development environments that mirror bleeding-edge PHP or MariaDB features, internal staging servers where you want to test compatibility ahead of an eventual RHEL migration, and environments where having the newest security patches and language features matters more than long-term stability.
If you’re running Fedora Server edition on bare metal or a VM specifically for a LAMP workload, just budget time for the upgrade cadence. Set a calendar reminder for end-of-life dates, because Fedora doesn’t wait around.
Prerequisites Before You Start
A few things should be sorted before touching a single dnf command:
- A fresh or updated Fedora 44 installation (Server, Workstation, or a minimal cloud image all work)
- Root or sudo access
- Basic familiarity with systemd and firewalld
- At least 2GB RAM for comfortable testing; production database workloads obviously need more
Start by making sure the system itself is current. Skipping this step is one of the most common reasons installations behave unpredictably later.
sudo dnf upgrade --refresh -y
The --refresh flag forces DNF to redownload repo metadata instead of relying on cached data, which matters right after a fresh install when metadata might be stale. If the kernel gets updated during this step, reboot before continuing.
sudo reboot
Step 1: Install Apache HTTP Server (httpd)
Fedora doesn’t call it “Apache” in the package name, it’s httpd. This trips up people coming from Debian-based systems where the package is literally named apache2.
sudo dnf install httpd -y
Once installed, enable and start it in one command:
sudo systemctl enable --now httpd
The --now flag saves you a step by combining enable and start into a single call, something that’s genuinely useful once you’ve typed systemctl enable X && systemctl start X a few hundred times over the years.
Verify it’s actually running, not just reporting “enabled”:
sudo systemctl status httpd
You want to see active (running) in green. If it says failed, check the logs immediately:
sudo journalctl -xeu httpd
Opening the Firewall for HTTP and HTTPS
Fedora ships with firewalld active by default, and unlike some quick-and-dirty tutorials that tell you to just disable it, that’s a bad habit to build. Open only the ports you need:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Confirm the rules took effect:
sudo firewall-cmd --list-services
You should see http and https in the output. If you’re planning to serve HTTPS later with a Let’s Encrypt certificate, opening https now saves a step down the line.
Testing Apache
Grab the server’s IP address:
ip a
Then hit it from a browser or curl locally:
curl http://localhost
You should get Fedora’s default Apache test page HTML back. If you get a connection refused error, it’s almost always one of three things: httpd isn’t actually running, the firewall is blocking port 80, or SELinux is denying the connection. We’ll cover SELinux troubleshooting further down because it deserves its own section.
Step 2: Install and Configure MariaDB
Fedora dropped MySQL from its default repositories years ago in favor of MariaDB, which is a fork maintained by many of the original MySQL developers after Oracle’s acquisition. For nearly all LAMP use cases, MariaDB is a drop-in replacement, and honestly, it performs better on read-heavy workloads in several benchmarks.
sudo dnf install mariadb-server -y
Enable and start the service:
sudo systemctl enable --now mariadb
Check the status:
sudo systemctl status mariadb
Securing the Installation
This step gets skipped more often than it should, especially on quick dev boxes, and that habit eventually bites people when a “temporary” test server ends up exposed to the internet. Run the secure installation script:
sudo mysql_secure_installation
You’ll be walked through a series of prompts:
- Set a root password (do this even on local dev machines, muscle memory matters)
- Remove anonymous users
- Disallow remote root login
- Remove the test database
- Reload privilege tables
Answer “Y” to all of these unless you have a specific reason not to. There’s rarely a good reason not to on any environment beyond a throwaway sandbox.
Creating a Dedicated Database and User
Never run your application against the root MariaDB account. It’s a bad practice that turns a minor SQL injection vulnerability into a full database compromise. Log in as root:
sudo mysql -u root -p
Then create a database and a scoped user:
CREATE DATABASE app_production CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'ReplaceWithAStrongPassword123!';
GRANT ALL PRIVILEGES ON app_production.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Note the utf8mb4 character set specifically. Plain utf8 in MySQL/MariaDB is actually a 3-byte implementation that can’t store emoji or certain multilingual characters correctly. utf8mb4 is the real, full 4-byte UTF-8 and should be your default for any new project in 2026, no exceptions.
Step 3: Install PHP and Common Extensions
PHP is where most confusion happens for people new to Fedora, mainly because the default repos ship a reasonably current PHP version, and different applications expect different extension sets.
Install PHP along with the extensions most real-world applications need:
sudo dnf install php php-cli php-fpm php-mysqlnd php-gd php-curl php-mbstring php-xml php-json php-opcache php-intl php-zip -y
Check what version landed:
php -v
Fedora 44’s repositories track current PHP stable branches, so you’re generally getting recent point releases with active security support, not something ancient that’s been end-of-lifed for years like you’d sometimes find on older enterprise distros.
Deciding Between mod_php and PHP-FPM
This is a genuinely important architectural decision, not just a config preference. Fedora’s default httpd package integrates with PHP through php-fpm (FastCGI Process Manager) rather than the older mod_php embedded approach used historically on many systems.
FPM runs PHP as a separate process pool, which has real advantages: better memory isolation, the ability to run multiple PHP versions side by side for different sites, and generally better performance under concurrent load because Apache’s worker processes aren’t tied up interpreting PHP directly.
Enable and start the FPM service:
sudo systemctl enable --now php-fpm
Verify Apache is configured to hand PHP requests off to FPM. Fedora typically drops a config snippet at /etc/httpd/conf.d/php-fpm.conf or similar during install, but double check:
sudo dnf install httpd
cat /etc/httpd/conf.d/*.conf | grep -i fpm
If nothing shows up, you may need to add a proxy handler manually:
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost"
</FilesMatch>
Restart both services after any config change:
sudo systemctl restart php-fpm httpd
Testing PHP Execution
Create a quick test file:
sudo tee /var/www/html/info.php > /dev/null <<'EOF'
<?php phpinfo(); ?>
EOF
Then browse to http://your-server-ip/info.php. You should see the full PHP configuration page. Once confirmed, delete it immediately. That file exposes a lot of environment detail that’s genuinely useful to an attacker doing reconnaissance.
sudo rm /var/www/html/info.php
SELinux: Don’t Just Disable It
Here’s where a lot of tutorials cut corners, and where a lot of production incidents actually originate. SELinux ships enforcing on Fedora by default, and it’s tempting when something doesn’t work to just run:
sudo setenforce 0
Don’t make that permanent habit. SELinux is doing real work protecting your webroot, your database sockets, and your process boundaries. The right approach is targeted context and boolean adjustments, not blanket disabling.
If Apache can’t write to a directory it needs (uploads folders, cache directories, log paths outside the default webroot), check what SELinux actually denied:
sudo ausearch -m avc -ts recent
Then set the correct context instead of disabling protection wholesale:
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/uploads(/.*)?"
sudo restorecon -Rv /var/www/html/uploads
If your app needs to make outbound network connections (calling an external API, sending mail through an SMTP relay), there’s a specific boolean for that instead of turning everything off:
sudo setsebool -P httpd_can_network_connect on
For database connectivity specifically:
sudo setsebool -P httpd_can_network_connect_db on
This is the difference between a hardened production server and one that just happens to work until someone actually tries to breach it.
Troubleshooting Common LAMP Stack Errors on Fedora
Apache Won’t Start After Installation
Run the journal log:
sudo journalctl -xeu httpd --no-pager
Common culprits are port 80 already in use (check with sudo ss -tulpn | grep :80), a syntax error in a custom vhost file, or a missing SSL certificate referenced in a config that hasn’t been created yet. Test config syntax before restarting:
sudo apachectl configtest
MariaDB Fails to Start With “Unable to Lock Database Directory”
This usually points to a permissions mismatch on /var/lib/mysql, often from a previous manual install or a botched restore from backup. Fix ownership:
sudo chown -R mysql:mysql /var/lib/mysql
sudo systemctl restart mariadb
PHP Files Downloading Instead of Executing
If browsing to a .php file prompts a download instead of rendering output, Apache isn’t routing PHP requests to the FPM handler correctly. Double-check the SetHandler directive mentioned earlier and confirm the FPM socket path matches what’s actually running:
sudo ls -la /run/php-fpm/
“403 Forbidden” on a Fresh Install
Nine times out of ten this is a SELinux context issue on the webroot, not a genuine permissions problem. Restore the default context:
sudo restorecon -Rv /var/www/html
If that doesn’t fix it, check actual file permissions too, Apache’s httpd process runs as the apache user by default on Fedora, and files need to be at least readable by that user or group.
Database Connection Refused From PHP
Confirm MariaDB is listening where PHP expects it:
sudo mysqladmin -u root -p status
Check whether php-mysqlnd is actually installed and enabled:
php -m | grep mysqlnd
Performance Tuning Worth Doing Before Go-Live
A default LAMP install works fine for testing, but production traffic exposes weaknesses fast. A few adjustments that consistently matter:
Apache worker configuration. If you’re on the traditional prefork MPM, tune MaxRequestWorkers based on available RAM. A rough formula: available memory divided by average per-process memory footprint (check with ps aux | grep httpd after some load). Running out of workers under a traffic spike causes queued connections and timeouts that look like the server crashed, when it’s actually just starved.
OPcache for PHP. This one gets skipped constantly and it’s a genuinely easy win. Edit /etc/php.ini or the dedicated opcache config:
opcache.enable=1
opcache.memory_consumption=192
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
Without OPcache, PHP recompiles every script on every request. With it enabled, you’re serving precompiled bytecode from memory, which on a busy WordPress or Laravel site can cut response times noticeably.
MariaDB buffer pool sizing. If InnoDB is your storage engine (it should be for anything modern), innodb_buffer_pool_size in /etc/my.cnf.d/mariadb-server.cnf should generally sit around 60-70% of available RAM on a dedicated database server:
[mysqld]
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
Disk I/O matters more than people expect. If MariaDB is on spinning disks instead of SSD/NVMe, query latency under concurrent load becomes a real bottleneck fast. Even on cloud VMs, check whether your storage tier supports the IOPS your workload demands, this is a frequent silent cause of “random slowness” that has nothing to do with the application code.
Enable HTTP/2. Apache on Fedora supports it through mod_http2, and enabling it, particularly alongside HTTPS, meaningfully improves page load performance for content-heavy sites through multiplexed connections.
Security Checklist Before Exposing the Stack Publicly
- Keep the system patched with
sudo dnf upgrade --refreshon a regular schedule, ideally automated withdnf-automaticfor security patches at minimum - Never expose MariaDB’s port 3306 to the public internet unless absolutely necessary; keep it bound to localhost or a private network
- Use
fail2banto block repeated failed login attempts against SSH and, with the right filters, against web application login endpoints too - Rotate database credentials periodically, especially after any staff turnover with server access
- Configure a proper TLS certificate through Let’s Encrypt and Certbot rather than serving anything sensitive over plain HTTP
- Disable directory listing in Apache unless there’s a specific reason to allow it (
Options -Indexesin your vhost config)