Rocky Linux’s AppStream Nginx package is built for conservative server maintenance, but nginx.org is the better source when you specifically need the current Mainline branch. Install Nginx Mainline on Rocky Linux from the official nginx.org RPM repository when you want upstream feature releases, DNF-managed updates, and packages that track the active mainline series instead of the distribution archive.
The nginx.org RPM repository currently supports Rocky Linux 10, 9, and 8 on x86_64 and aarch64/arm64. Its stable and mainline branches share one repository file, so a server can keep mainline enabled for new releases while retaining a documented path back to stable if your workload needs the slower branch.
Install Nginx Mainline on Rocky Linux
Refresh package metadata and apply pending updates before changing the web server package source.
sudo dnf upgrade --refresh
Use an account with sudo privileges for the remaining administrative tasks.
If Nginx is already installed from Rocky Linux AppStream, EPEL, or another third-party repository, back up any configuration you want to keep before removing the package. The nginx.org package uses /etc/nginx/nginx.conf and /etc/nginx/conf.d/, so existing files can affect the new service.
if [ -d /etc/nginx ]; then
sudo cp -a /etc/nginx "/etc/nginx.backup.$(date +%F)"
fi
Stop and remove the current package only when Nginx is already present. Skipping this step is fine on a fresh Rocky Linux server.
if rpm -q nginx >/dev/null 2>&1; then
sudo systemctl disable --now nginx || true
sudo dnf remove nginx
fi
Install Repository Management Tools
The dnf config-manager plugin comes from dnf-plugins-core on Rocky Linux. Install it before creating the repository file or switching repository branches.
sudo dnf install dnf-plugins-core
Create the nginx.org Repository File
The nginx.org Linux packages documentation publishes RHEL-compatible packages under a centos path. Keep $releasever and $basearch literal in the file so DNF selects the correct Rocky Linux major release and CPU architecture.
sudo tee /etc/yum.repos.d/nginx.repo >/dev/null <<'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=https://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=https://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
DNF imports nginx.org signing keys during the first package transaction. The nginx.org RPM documentation lists
573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62as the fingerprint to verify, and the key file can contain additional nginx signing keys used for newer packages.
Verify the Mainline Repository
Confirm that DNF sees the mainline repository and that the latest Nginx package comes from nginx-mainline, not Rocky Linux AppStream.
dnf repolist --enabled | grep -E '^nginx-mainline'
dnf repoquery --repoid=nginx-mainline --latest-limit=1 --available nginx --qf '%{name} %{version}-%{release} %{repoid} %{arch}'
As of May 15, 2026, a Rocky Linux 9 x86_64 package entry looked like this; the release suffix changes to el8.ngx, el9.ngx, or el10.ngx depending on the Rocky release.
nginx-mainline nginx mainline repo nginx 1.31.0-1.el9.ngx nginx-mainline x86_64
DNF resolves package dependencies automatically. On Rocky Linux 8, the current nginx.org package requires common runtime libraries such as OpenSSL 1.1, PCRE2, zlib, procps-ng, shadow-utils, and systemd; avoid downloading individual dependency RPMs by hand unless you are building an offline mirror.
dnf repoquery --repoid=nginx-mainline --latest-limit=1 --requires nginx | sort
Install Nginx Mainline
Install the Nginx package from the enabled mainline repository. Review the package summary and GPG key prompt before accepting.
sudo dnf install nginx
Check the installed package and runtime version after the transaction completes. Version numbers move with nginx.org releases, but the package should use the el8.ngx, el9.ngx, or el10.ngx suffix for your Rocky Linux release.
rpm -q nginx
nginx -v
nginx-1.31.0-1.el9.ngx.x86_64 nginx version: nginx/1.31.0
Prepare the SELinux PID File
Rocky Linux runs SELinux in enforcing mode by default. Current nginx.org RPMs can fail under systemd if /run/nginx.pid is created with the generic var_run_t context, so create a systemd-tmpfiles rule that recreates and labels the PID file as httpd_var_run_t at boot.
sudo tee /etc/tmpfiles.d/nginx-pid.conf >/dev/null <<'EOF'
f /run/nginx.pid 0644 root root -
z /run/nginx.pid 0644 root root -
EOF
sudo systemd-tmpfiles --create /etc/tmpfiles.d/nginx-pid.conf
The label should show httpd_var_run_t before the service starts.
ls -Z /run/nginx.pid
system_u:object_r:httpd_var_run_t:s0 /run/nginx.pid
Start and Verify Nginx
Test the generated configuration before starting the daemon.
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Enable and start Nginx with one systemd transaction, then verify both the current state and the boot setting.
sudo systemctl enable --now nginx
systemctl is-active nginx
systemctl is-enabled nginx
active enabled
A local HTTP probe confirms that the default listener answers on port 80.
curl -fsSI http://127.0.0.1/ | sed -n '1p'
HTTP/1.1 200 OK
The nginx.org package runs worker processes as the nginx user by default, which matters when you set web root ownership and read permissions later.
Allow Web Traffic Through Firewalld
Rocky Linux commonly ships with firewalld enabled. Open HTTP and HTTPS only when the server should accept web traffic from other machines.
Opening ports 80 and 443 exposes the server to network traffic. Before using the service for production, review virtual hosts, file permissions, TLS certificates, and Nginx security headers.
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload
Query the service entries instead of relying on a host-specific service list.
sudo firewall-cmd --zone=public --query-service=http
sudo firewall-cmd --zone=public --query-service=https
yes yes
Compare Nginx Stable and Mainline Branches
nginx.org lists mainline 1.31.0 and stable 1.30.1 as of May 15, 2026. Treat point releases as moving values and verify with nginx -v or the Nginx download page before recording a version in change tickets or deployment notes.
| Branch | Current role | Use it when |
|---|---|---|
| Mainline | Active feature branch with regular bug fixes and new functionality | You want the newest nginx.org features and can follow normal package updates |
| Stable | Slower branch focused on critical bug and security fixes | You prefer fewer feature changes on conservative production servers |
The nginx.org project recommends the mainline branch for most users, while stable remains available for administrators who want a slower branch. Both branches are official nginx.org packages; choose one enabled branch at a time to keep DNF’s package source predictable.
Switch Between Mainline and Stable
The repository file already defines both branches. To move from mainline to stable, stop Nginx, remove the package, switch enabled repositories, reinstall, and start the service again. Configuration files under /etc/nginx remain on disk unless you delete them separately.
sudo systemctl disable --now nginx
sudo dnf remove nginx
sudo dnf config-manager --set-disabled nginx-mainline
sudo dnf config-manager --set-enabled nginx-stable
sudo dnf install nginx
sudo systemd-tmpfiles --create /etc/tmpfiles.d/nginx-pid.conf
sudo systemctl enable --now nginx
nginx -v
The version should now report the stable branch. At the time of this audit, stable reported:
nginx version: nginx/1.30.1
Reverse the enabled repositories to return to mainline.
sudo systemctl disable --now nginx
sudo dnf remove nginx
sudo dnf config-manager --set-disabled nginx-stable
sudo dnf config-manager --set-enabled nginx-mainline
sudo dnf install nginx
sudo systemd-tmpfiles --create /etc/tmpfiles.d/nginx-pid.conf
sudo systemctl enable --now nginx
nginx -v
The version should return to the mainline branch. At the time of this audit, mainline reported:
nginx version: nginx/1.31.0
Update Nginx Mainline
The nginx.org repository integrates with normal DNF updates. Refresh metadata, upgrade the package, and restart Nginx so the running master process uses the new binary.
sudo dnf upgrade --refresh nginx
sudo systemctl restart nginx
nginx -v
Use reload for configuration-only changes, but use restart after package upgrades because the executable changes on disk.
Remove Nginx Mainline and nginx.org Repository
Stop the service and remove the package first. The rpm -q check gives a package-manager proof that Nginx is no longer installed.
sudo systemctl disable --now nginx
sudo dnf remove nginx
rpm -q nginx || true
package nginx is not installed
Remove the nginx.org repository file and the SELinux PID-file tmpfiles rule.
sudo rm -f /etc/yum.repos.d/nginx.repo
sudo rm -f /etc/tmpfiles.d/nginx-pid.conf /run/nginx.pid
dnf repolist --enabled | grep -E '^nginx-(mainline|stable)' || echo "nginx.org repositories are not enabled"
nginx.org repositories are not enabled
Delete configuration files only when you no longer need any virtual hosts, certificates stored under /etc/nginx, snippets, or custom logging paths.
sudo rm -rf /etc/nginx
DNF can leave nginx.org GPG public keys in the RPM database after repository removal. Remove the matching key packages only when this server no longer uses nginx.org RPM repositories.
rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\n' \
| grep -Ei '7bd9bf62|b49f6b46|8d88a2b3' \
| xargs --no-run-if-empty sudo rpm -e
Troubleshoot Nginx Mainline on Rocky Linux
Nginx Fails with /run/nginx.pid Permission Denied
If systemd reports open() "/run/nginx.pid" failed (13: Permission denied), inspect the unit logs and confirm that the PID file has the SELinux type prepared earlier.
journalctl -u nginx --no-pager -n 40
ls -Z /run/nginx.pid
Recreate the labeled PID file and restart Nginx.
sudo systemd-tmpfiles --create /etc/tmpfiles.d/nginx-pid.conf
sudo systemctl restart nginx
If /etc/tmpfiles.d/nginx-pid.conf is missing, recreate the file from the SELinux PID-file step before restarting.
DNF Still Selects the Rocky Linux Package
If DNF chooses an AppStream package or cannot see the mainline branch, verify the repository state and clean stale metadata.
sudo dnf config-manager --set-disabled nginx-stable
sudo dnf config-manager --set-enabled nginx-mainline
sudo dnf clean metadata
dnf repoquery --repoid=nginx-mainline --latest-limit=1 --available nginx --qf '%{name} %{version}-%{release} %{repoid}'
The repository file also needs module_hotfixes=true in both nginx.org entries so DNF can prefer the external package over modular AppStream packages.
Repository Metadata Returns 404 Errors
Repository 404 errors usually mean the URL variables were expanded while creating the file or the Rocky major release is not in nginx.org’s supported RHEL-derivative matrix. The baseurl lines must keep the literal variables.
grep -A6 '^\[nginx-mainline\]' /etc/yum.repos.d/nginx.repo
[nginx-mainline] name=nginx mainline repo baseurl=https://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true
Recreate the repository file with the quoted heredoc syntax if the dollar signs are missing.
Rocky Linux 8 Dependency Resolution
Rocky Linux 8 remains supported by the nginx.org RHEL-derivative repository, and DNF resolves the current mainline package dependencies from enabled repositories. If dependency resolution fails, check that Rocky BaseOS and AppStream repositories are enabled before looking for third-party RPM files.
dnf repolist --enabled
dnf repoquery --repoid=nginx-mainline --latest-limit=1 --requires nginx | sort
Port 80 Is Already in Use
A bind error means another process already owns the HTTP listener. Identify the process before changing Nginx ports; if the users column shows httpd, Apache is using port 80.
sudo ss -tlnp | grep ':80'
Stop the conflicting service or move one service to another port. Use the Nginx port change guide when Nginx should listen on a non-standard port.
sudo systemctl stop httpd
sudo systemctl restart nginx
Firewalld Is Not Running
If firewall-cmd reports that firewalld is not running, start and enable the service before adding HTTP and HTTPS rules. Cloud providers may also require a matching security-group or network-firewall rule outside Rocky Linux.
systemctl is-active firewalld
sudo systemctl enable --now firewalld
Configuration Syntax Errors
Syntax errors show the affected file and line number. Fix the configuration and test again before restarting or reloading the service.
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Next Steps After Installing Nginx Mainline
Nginx Mainline is now installed from nginx.org, managed by DNF, prepared for SELinux-enforcing startup, and reachable through firewalld. Common follow-up work includes installing PHP on Rocky Linux, enabling gzip compression, or placing an application behind an Nginx reverse proxy.
After traffic reaches the server, status-code troubleshooting becomes more useful than install checks. Use the Nginx 403 Forbidden, Nginx 404 Not Found, and Nginx 502 Bad Gateway references when browser requests hit Nginx but return an application or upstream error.
Conclusion
Nginx Mainline is running on Rocky Linux from the nginx.org repository, with DNF handling updates and a systemd-tmpfiles rule keeping SELinux startup reliable. Keep one nginx.org branch enabled at a time, restart after package upgrades, and use the package-source checks whenever DNF output does not match the expected mainline branch.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>