How to Install Nginx Mainline on Rocky Linux 10, 9 and 8

Install Nginx Mainline on Rocky Linux 10, 9 and 8 using the official repository. Covers firewall setup, branch switching, and troubleshooting.

Last updatedAuthorJoshua JamesRead time6 minGuide typeRocky Linux

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 BF62 as 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.

BranchCurrent roleUse it when
MainlineActive feature branch with regular bug fixes and new functionalityYou want the newest nginx.org features and can follow normal package updates
StableSlower branch focused on critical bug and security fixesYou 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.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Verify before posting: