
Fedora 44 is a strong platform for modern web hosting because it stays close to upstream packages, moves quickly on PHP and MariaDB availability, and gives you current versions without the baggage of old repository habits. A LEMP stack on Fedora 44 is a practical choice when you want a lean web server, fast PHP handling, and a database layer that is easy to maintain, secure, and tune for real traffic.
What usually surprises people is that the installation is the easy part. The real work starts after the services come up: aligning Nginx with PHP-FPM, making sure MariaDB is not exposed unnecessarily, checking SELinux behavior, opening only the firewall ports you actually need, and tuning the stack so it behaves well under load instead of only passing a localhost test. Fedora’s docs and current Fedora-specific guides reflect that approach: install the base packages, enable the services, and then harden, monitor, and verify the whole chain end to end.
What LEMP means
LEMP stands for Linux, Nginx, MariaDB, and PHP. On Fedora 44, that combination works especially well for WordPress, Laravel, Symfony, custom PHP applications, and lightweight dynamic sites that need better concurrency than a traditional Apache setup.
Nginx handles static assets efficiently and pairs cleanly with PHP-FPM, while MariaDB provides a mature SQL backend that Fedora treats as a preferred MySQL-compatible option. Fedora’s own developer portal notes that MariaDB is the preferred MySQL implementation in Fedora and can usually act as a drop-in replacement in practical deployments.
Before you begin
Use a fresh Fedora 44 server or VM with sudo access. A minimum of 2 GB RAM is workable for testing, but 4 GB or more is a far more comfortable starting point if you expect a real WordPress site, a caching plugin, or concurrent traffic bursts.
Update the system first, because starting from a patched base avoids chasing weird dependency problems later.
sudo dnf upgrade --refresh -y
sudo reboot
After reboot, confirm you are on Fedora 44 and have connectivity.
cat /etc/fedora-release
ip a
Install Nginx
Start with the web server. Nginx is available directly from Fedora’s repositories, and the package installs cleanly with DNF. Fedora’s deployment guidance for Nginx and PHP follows the same basic path: install packages, start services, and verify the HTTP path before expanding the stack.
sudo dnf install -y nginx
Enable and start the service.
sudo systemctl enable --now nginx
Check status right away.
sudo systemctl status nginx --no-pager
If Nginx is healthy, you should see it listening on port 80. A quick test from the server itself is enough for first validation.
curl -I http://localhost
At this point, Fedora’s firewall may still block external traffic. That is expected. The service can be running perfectly and still look “down” from another machine because the port is closed at the network layer.
Install MariaDB
MariaDB is usually the database layer I prefer for a standard LEMP deployment on Fedora when the goal is compatibility, stability, and low maintenance overhead. Fedora’s documentation says the default MariaDB server can be installed directly with dnf install mariadb-server, and it notes that MariaDB runs on port 3306 with data under /var/lib/mysql.
Install it.
sudo dnf install -y mariadb-server
Enable and start it.
sudo systemctl enable --now mariadb
Check that it initialized correctly.
sudo systemctl status mariadb --no-pager
Run the post-install hardening routine. This matters more than people think, because the default MariaDB install is meant to get you running, not to act as a finished production configuration. Fedora’s docs explicitly recommend strong passwords, least privilege, SELinux enforcement, updates, and log monitoring for production use.
sudo mysql_secure_installation
A sensible baseline is:
- Set a root password if prompted.
- Remove anonymous users.
- Disallow remote root login.
- Remove the test database.
- Reload privilege tables.
For local development or a single-server application, keep MariaDB listening only on localhost unless you have a specific remote database requirement. If you need remote access later, bind carefully and open port 3306 only to trusted sources. Fedora documents both the firewall step and the bind-address configuration model for remote access.
Install PHP and PHP-FPM
Fedora’s PHP packages are straightforward to install, and the Fedora Developer Portal notes that dnf install php-cli gets you the core PHP runtime, while additional extensions are installed separately with php- prefixed packages.
For a typical LEMP stack, install PHP-FPM plus the extensions most web apps need.
sudo dnf install -y php php-fpm php-cli php-mysqlnd php-opcache php-gd php-xml php-mbstring php-curl php-zip
If you are building a WordPress or CMS server, php-mysqlnd, php-xml, php-mbstring, php-curl, and php-opcache are usually non-negotiable. If the app needs image handling, keep php-gd; if it uses archive handling or Composer-heavy workflows, php-zip helps. The exact set depends on the application, but the point is the same: install only what the application truly needs, because smaller surfaces are easier to secure and debug.
Enable and start PHP-FPM.
sudo systemctl enable --now php-fpm
Check the service.
sudo systemctl status php-fpm --no-pager
Configure PHP-FPM
Fedora’s PHP package layout is modern, but the defaults are still worth reviewing before placing production traffic on the box. On many PHP-FPM installs, the key files are under /etc/php-fpm.d/ and the main pool is usually www.conf. You want to confirm whether the pool listens on a socket or on TCP, because Nginx has to match that exactly.
Open the pool configuration.
sudo grep -E '^(user|group|listen|pm\.)' /etc/php-fpm.d/www.conf
A socket-based setup is usually cleaner on a single server because it avoids unnecessary TCP overhead on localhost. If your pool is configured for a socket, the Nginx upstream block will point to that socket path. If it uses 127.0.0.1:9000, keep it consistent. Fedora’s older deployment guidance uses 127.0.0.1:9000, while modern setups often prefer Unix sockets for local performance and simpler access control.
A practical baseline for a small to medium site is:
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
These are not magic numbers. They are a starting point, and you should adjust them based on memory use, response time, and actual traffic patterns. That is the difference between a tutorial config and a production config: the production config gets tuned after observing the system under load.
Configure Nginx for PHP
Now connect Nginx to PHP-FPM. This is where most first-time setups either work cleanly or fail with a blank page and a permission error. Fedora’s PHP/Nginx deployment references show the standard pattern: define the site root, ensure index.php is included, and pass PHP requests to PHP-FPM with a correct SCRIPT_FILENAME.
Create a new server block.
sudo nano /etc/nginx/conf.d/example.conf
Use a configuration like this:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.php index.html;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php-fpm/www.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp)$ {
expires 30d;
access_log off;
log_not_found off;
}
location ~ /\. {
deny all;
}
}
If your PHP-FPM pool listens on 127.0.0.1:9000, change the fastcgi_pass line to that address. The Nginx/PHP pair must match exactly.
Create the site directory and a test file.
sudo mkdir -p /var/www/example.com/html
echo "<?php phpinfo(); ?>" | sudo tee /var/www/example.com/html/info.php
sudo chown -R nginx:nginx /var/www/example.com
sudo chmod -R 755 /var/www/example.com
That ownership choice is practical for many Fedora Nginx setups, though some administrators prefer different deployment users for stricter separation. The important part is that Nginx and PHP-FPM can both read the content while keeping write access tightly controlled.
Test the configuration before reloading.
sudo nginx -t
If the syntax is clean, reload Nginx.
sudo systemctl reload nginx
Open the firewall
A very common mistake is to assume the service is broken when the firewall is actually doing its job. Fedora’s documentation and deployment examples show opening HTTP with firewall-cmd --permanent --add-service=http and then reloading the firewall.
Do that now.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Verify the active rules.
sudo firewall-cmd --list-services
If this is only a local test server, you may not need HTTPS immediately, but in real production you almost always will. It is better to add the port now and enable TLS once DNS is ready than to forget it and debug a mysterious access issue later.
Verify the stack
At this stage, the stack should be alive:
- Nginx accepts requests.
- PHP-FPM handles
.phpfiles. - MariaDB is running in the background.
- The firewall allows inbound web traffic.
From another machine, open:
http://your-server-ip/info.php
If PHP works, you will see the PHP info page. Delete that file afterward, because exposing full PHP information publicly is unnecessary risk.
sudo rm -f /var/www/example.com/html/info.php
This is a small but important habit. PHP info pages are useful for validation, and they are a liability once the test is complete.
Secure the server
Security is not an optional final step. It is part of the installation. Fedora’s MariaDB guidance explicitly calls out enforcing SELinux, limiting privileges, using strong passwords, and monitoring logs in production.
A solid baseline includes:
- Keep SELinux enforcing.
- Disable direct root login over the network.
- Use separate database users for each application.
- Restrict the web root permissions.
- Keep packages updated.
- Expose only 80/443 publicly.
Check SELinux mode.
getenforce
If it is not Enforcing, fix the policy issue instead of turning SELinux off. That may feel faster in the moment, but it usually creates a technical debt problem that surfaces later as a security incident.
For a web root, a common pattern is:
- Files owned by a deploy user.
- Read access for Nginx/PHP-FPM.
- Writable directories only where the app genuinely needs them.
For WordPress, that often means writable wp-content/uploads only, not the full codebase.
SELinux issues
SELinux is where many good Fedora installs go sideways, especially after a configuration move. If Nginx can load static files but PHP returns 502 or permission denied errors, the issue may be context labeling rather than Unix permissions. Fedora’s guidance on MariaDB and Nginx both emphasize using SELinux correctly in production rather than bypassing it.
Useful commands:
sudo ausearch -m avc -ts recent
sudo journalctl -xeu php-fpm
sudo journalctl -xeu nginx
If you relocate web content outside standard paths, you may need to label it properly.
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.com
If PHP needs write access to specific directories, such as uploads or cache folders, label only those directories for writable web content. Keep the rest read-only. That gives you a better security posture and fewer surprises during an audit.
MariaDB tuning
MariaDB on Fedora can run comfortably with defaults for small workloads, but the defaults are not always ideal for busy sites. Fedora’s docs point out where data lives and note that configuration is handled through /etc/my.cnf and /etc/my.cnf.d/*.cnf, which is the right place for persistent tuning changes.
A simple tuning file:
sudo nano /etc/my.cnf.d/server.cnf
Example settings:
[mysqld]
bind-address = 127.0.0.1
max_connections = 100
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
tmp_table_size = 64M
max_heap_table_size = 64M
slow_query_log = 1
slow_query_log_file = /var/log/mariadb/slowquery.log
For a real production system, size innodb_buffer_pool_size according to total RAM and workload. On a dedicated database host, it can consume a large share of memory. On a combined web/database host, be more conservative because PHP-FPM, Nginx, the kernel page cache, and other services all need room.
After changes:
sudo systemctl restart mariadb
Then watch for errors.
sudo journalctl -u mariadb -n 50 --no-pager
PHP performance
PHP-FPM performance often decides whether the stack feels snappy or sluggish under traffic. One of the biggest wins is enabling OPcache, which reduces repeated script compilation overhead. The Fedora PHP package set includes php-opcache, and that should be active in almost every production deployment.
Check the OPcache settings.
php -i | grep -i opcache
A common tuning file is under /etc/php.d/10-opcache.ini or a similar path depending on packaging. Baseline options often include:
- Higher
opcache.memory_consumption. - Reasonable
opcache.max_accelerated_files. opcache.validate_timestampstuned according to deployment style.
If you deploy code through Git or CI/CD, you can often keep timestamps enabled and still enjoy good performance. If you run immutable releases, you can tune more aggressively. The key is not copying random values from a blog and forgetting to revisit them after the workload changes.
Nginx performance
Nginx does best when you keep the configuration simple and intentional. That means proper caching for static assets, compression where appropriate, and sane worker settings. For many Fedora servers, the default worker model is already good enough, but you still want to verify that file descriptors, keepalive behavior, and gzip are not limiting throughput.
Useful additions in /etc/nginx/nginx.conf:
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
types_hash_max_size 4096;
gzip on;
gzip_types text/plain text/css application/javascript application/json application/xml image/svg+xml;
}
Do not blindly crank values upward. Match them to CPU cores, RAM, and the expected traffic pattern. A server serving mostly static assets benefits from different tuning than a PHP-heavy WordPress site with many logged-in users.
Production use cases
A Fedora 44 LEMP stack fits several real-world scenarios well. It is a good base for:
- WordPress hosting with Nginx and PHP-FPM.
- Laravel or Symfony apps behind a reverse proxy or directly on Nginx.
- Internal dashboards and admin panels.
- API backends that need a lean web front end.
- Low-to-medium traffic sites where you want modern packages and manageable maintenance.
For a WordPress site, the LEMP approach is often cleaner than a default LAMP setup because Nginx handles high concurrency and static files efficiently. For a traffic spike, the limiting factor is usually not Nginx itself, but PHP-FPM concurrency, database contention, and disk I/O. That is why production tuning should always look at the whole chain, not just the web server.
Common errors
502 Bad Gateway
This usually means Nginx can reach the socket or port poorly, or PHP-FPM is down. First check whether PHP-FPM is running.
sudo systemctl status php-fpm --no-pager
Then inspect the socket path in your Nginx config and the listen directive in PHP-FPM. A mismatch is one of the most common causes of this error.
Permission denied
If static files load but PHP fails, you may have a file ownership issue or SELinux denial. Check both Unix permissions and SELinux logs before changing anything else.
Database connection failed
Confirm MariaDB is running and that the application is using the correct host, username, password, and database name.
sudo systemctl status mariadb --no-pager
mysql -u root -p
If remote access is involved, confirm bind-address, firewall policy, and database grants. Fedora’s MariaDB documentation recommends narrowing remote access as much as possible and keeping the service local when remote access is unnecessary.
Page downloads instead of runs
This usually means PHP is not being passed to PHP-FPM correctly. Check the location ~ \.php$ block, the fastcgi_pass target, and the SCRIPT_FILENAME parameter. That one line can decide whether a site works or fails silently.
Maintenance routine
A good LEMP stack is not “installed once and forgotten.” It needs a simple maintenance cadence. Weekly updates, log checks, and occasional performance reviews are enough for many small production servers. Fedora ships current packages, which is great for features and security, but it also means you should patch consistently instead of letting upgrades pile up.
A practical routine:
- Apply security updates regularly.
- Review
nginx,php-fpm, andmariadblogs. - Monitor disk growth under
/var/lib/mysqland web logs. - Check free memory and swap.
- Test backups and restore procedures.
Useful commands:
sudo dnf upgrade --refresh
sudo journalctl -u nginx -n 100 --no-pager
sudo journalctl -u php-fpm -n 100 --no-pager
sudo journalctl -u mariadb -n 100 --no-pager
df -h
free -m
ss -tulpn
If this is a production server, monitoring tools like htop, iotop, iftop, sar, mariadb-admin, and log analysis with journalctl are still some of the most useful tools on the box. They tell you what is really happening instead of what a control panel claims is happening.