How to Change SSH Port for SELinux and firewalld
For Rocky Linux or AlmaLinux, change sshd port without lockout: open firewalld first, label am with semanage, edit sshd_config, then restart.
Why changing the SSH port need three steps here
To change SSH port for Rocky Linux, AlmaLinux, CentOS Stream or Fedora, one edit no dey enough. Three different systems each get say for whether connection on the new port go work. firewalld decide whether packet go reach the machine. SELinux decide whether sshd fit bind that port number at all. sshd_config decide which port the daemon go request. If you miss the SELinux step, the daemon no go start. If you miss the firewalld step, e go start and listen, but nobody go fit reach am.
For Ubuntu, na one edit and restart dey do the same work, because Ubuntu dey use AppArmor instead of SELinux and e no ship profile wey restrict which ports sshd fit bind. If ufw dey run there, add one rule. Na the whole difference be that. The RHEL family dey ship with firewalld running and SELinux enforcing for fresh install, and both of dem care about port numbers.
Do the work for this order and your current session go remain alive through every step:
- Open the new port for firewalld, but leave port 22 open for now.
- Add the SELinux label for the new port with
semanage. - Set the port inside sshd configuration.
- Restart
sshd, then log in through the new port from a second terminal before you close the first one.
Find your provider's web console (VNC or serial) before you start, and confirm say you fit log in through am. That console na your way back in if the change go wrong. Port change na one of the commonest reasons tenant lock themselves out of server wey dem just pay for.
Ferst, install semanage
semanage na the tool wey dey edit SELinux policy settings, but minimal Rocky Linux or AlmaLinux install no include am. E dey inside policycoreutils-python-utils.
sudo dnf install -y policycoreutils-python-utilsIf you run the command before you install that package, e go show sudo: semanage: command not found. Na for this point many readers dey decide say SELinux no dey installed and skip the step. SELinux dey installed. Na only the management tool dey missing. If dnf syntax still new to you, the equivalent dnf and apt commands go connect am to wetin you already know.
Port wan wey you go use, then check say nothing dey own am
Any free TCP port from 1024 to 65535 go work. Do these two checks before you settle for one:
sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222The first command show whether any process dey listen for that number. The second one show whether SELinux policy don already assign am to another service type. Free port go return nothing from both commands. If policy don already claim am, the semanage port -a for step 2 go fail with ValueError: Port tcp/2222 already defined, and you need choose another number.
We use 2222 as example throughout this guide. Scanner also dey try am as the first port after 22, so for real server, choose a number wey no too obvious.
Step 1: open port for firewalld
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports--permanent dey write the rule inside the zone file for disk, but e no touch the firewall wey dey run. --reload dey load the configuration wey dey for disk enter the firewall wey dey run. If you skip the reload, the rule go exist but e no go do anything until firewalld restart again. Na one of the commonest reasons this whole process fit look like say e fail for no reason.
Leave the ssh service entry as e be for now. Na this entry dey keep port 22 open, and e be your fallback while you dey test.
Check your provider control panel too. Plenty hosts dey run network firewall for front of the VPS, outside the operating system. So port wey you open for firewalld still fit get dropped upstream. The firewalld basics guide for a VPS explain zones and the difference between runtime and permanent configuration if this model new to you.
Step 2: label the port for SELinux
sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t-a dey add new port assignment. -t ssh_port_t na the type wey SSH ports dey carry. The second command list everything wey ssh_port_t don cover now, so you fit confirm say your number enter before you touch the daemon.
Wetin make SELinux block the port at all
SELinux (security-enhanced Linux) dey give every object for the system one label, and TCP port numbers na objects like every other one. SSH daemon dey run inside one domain wey dem call sshd_t. Policy allow sshd_t bind TCP ports wey get ssh_port_t label, and by default na only port 22 get that label. If you tell the daemon make e bind 2222, kernel go check the label, see the generic type wey policy assign to that number, then refuse name_bind permission for the socket.
Na why this failure no look like firewall problem. Kernel dey refuse am before any listening socket fit exist, so sshd report the error and exit. Firewall problem na the opposite: daemon dey run well, but packets dey get discarded as dem dey enter.
getenforce go tell you the mode wey the box dey use. For Permissive, system go record denial but e no enforce am, so port change go look like say e work, then e go break the day person run setenforce 1 or the box reboot into enforcing mode. Label the port for either mode. The SELinux basics guide for a server explain modes, contexts and booleans properly. Ports no be the only objects wey this fit affect. The same policy fit stop container from reading mounted host directory until dem relabel that path. Na why installing Docker on Rocky Linux or AlmaLinux get one SELinux step wey Ubuntu guides no dey mention.
Step 3: set port for sshd configuration
For Rocky Linux 9 and 10, AlmaLinux 9 and 10, and current Fedora, /etc/ssh/sshd_config dey start with an include line, so the clean place to put your change na for a drop-in file. Package updates no go clash with your edit.
grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -tIf grep no find any Include line, as e dey happen for Rocky Linux 8 and other older images, put Port 2222 directly inside /etc/ssh/sshd_config instead. sshd -t go parse the complete configuration, including drop-ins, and report syntax errors. Fix everything wey e report before you restart, because if configuration no parse, daemon no go come back up.
Port fit show more than once, and sshd go listen on every port wey you list. Keep Port 22 together with Port 2222 for the first day as cheap safety net, as long as you remember to remove am.
sshd dey start through socket unit?
Some images dey start SSH through systemd socket activation instead of long-running service. For this setup, systemd dey own the listening socket and hand connections over to sshd, so Port line for sshd_config no get any effect at all. Check this before you restart anything:
systemctl is-enabled sshd.socketIf answer show enabled, e mean say dem set the port for socket unit, no be for sshd_config:
sudo systemctl edit sshd.socket[Socket]
ListenStream=
ListenStream=2222You must include the bare ListenStream=. Values dey add together across drop-ins. So if you no first use empty assignment clear the list, the socket go still listen on 22 and 2222. Apply am with sudo systemctl daemon-reload, then run sudo systemctl restart sshd.socket. If the unit disabled or e no dey for your server, this section no apply to you.
Step 4: restart, then test from a second terminal
sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshdMake you keep this terminal open. No log out from am. Open another terminal for your own machine and connect through the new port:
ssh -p 2222 youruser@203.0.113.10Close the first session only after the second login don work. If e no work, you still get one shell wey you fit use undo everything. This one habit na the difference between change wey take five minutes and spending whole afternoon for provider console.
Firewall drop or SELinux denial? How to tell dem apart
From your laptop, the two failures go look almost the same. But for the server, dem no resemble each other at all.
- If
systemctl status sshdshow say the unit fail, the daemon never get its socket. Na configuration error or SELinux denial cause am. - If the unit dey active and
ss -tlnpshow say sshd bind to the new port, the daemon dey okay. The problem dey for the network path: firewalld, the provider separate firewall, or the address and port wey you dial.
For the SELinux case, read the audit record instead of guessing:
sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pagerA name_bind denial for class tcp_socket name the process for comm="sshd", the port number for src=, and the label wey the port actually carry for tcontext=. That last field na the answer. Anything wey no be ssh_port_t mean say step 2 no apply to the port wey you dey use. Most times, na typo for the number or wrong protocol cause am. Install setroubleshoot-server if you prefer make sealert turn the record into sentence.
The message wey sshd itself write when the kernel refuse the bind look like this:
error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.Permission denied for a port above 1024, where root privilege no dey needed to bind, na the SELinux signature. Address already in use for that same line na another fault: another process dey hold the port. From the client side, the difference between connection refused and connection timed out help separate the two network cases. Connection refused mean say your packet reach the host and nothing dey listen. Timeout mean say nothing answer at all.
Close port 22 and update your clients
Once several logins on the new port don work, remove 22:
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-allLeave the SELinux label for port 22 as e be. Na base policy provide am, and e no grant anything again once firewall stop allowing packets enter.
Then update the clients, because every tool wey assume the default port now need instruction. Put am for ~/.ssh/config for your own machine one time, instead of typing -p every time:
Host myvps
HostName 203.0.113.10
Port 2222
User youruserscp, sftp, rsync and Ansible all dey read that file. Backup jobs, monitoring checks and cron scripts wey hardcode port 22 no dey read am, so find and update dem while the change still fresh for your head.
Wetin changing the port fit do and wetin e no fit do
E go reduce log noise. Automated scanners dey hammer port 22 constantly, and moving away from am go remove most of those lines from the journal, so real events go easier to see. E no be security control. Any scanner wey dey sweep the full port range go find your daemon and read its version banner anyway. Treat the port change as housekeeping, and put the real protection for key-only authentication with password logins turned off. the SSH hardening guide for a VPS explain the steps one by one.
Everything above dey work the same way for both major RHEL rebuilds, because dem build am from the same sources. See Rocky Linux and AlmaLinux compared if you still dey choose between dem. The reason why two near-identical rebuilds dey available na because CentOS stop being one for 2020. the story from Red Hat to CentOS to Rocky and AlmaLinux tell the full story. Check the release wey dem actually give you before you follow any older guide, with cat /etc/os-release. Guides wey dem write for Rocky Linux 8 still rank well, and their semanage and firewall-cmd steps still correct. But Rocky 8 no get sshd_config.d include line and no socket unit to consider, so the sshd part of those guides no match current box.
fail2ban need know about the new port
fail2ban no dey inside the base repositories. E dey come from EPEL (extra packages for enterprise Linux):
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalldThe fail2ban-firewalld subpackage make fail2ban write its bans through firewalld. Na this one you want for machine where firewalld dey control the ruleset.
The stock sshd jail set port = ssh, and that name resolve through /etc/services to 22. After your change, the jail dey monitor port wey nobody dey attack. So e no go ban anybody, while failed logins dey pile up for 2222. Set the port with the number inside /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600backend = systemd dey read failures from the journal instead of /var/log/secure. This one safer for minimal install where rsyslog fit no dey available. Start am with sudo systemctl enable --now fail2ban and inspect the jail with sudo fail2ban-client status sshd. The jail syntax na the same one wey dem use for fail2ban setup for SSH on Ubuntu 24.04. Na only the package source and ban action different.
Patching matter pass the port
Server wey dem move SSH port for, but e get four months security updates wey dem never apply, dey worse pass one wey still dey use port 22 but dey patch itself every night. Turn on unattended updates for the same session, while you still be root: automatic dnf updates for Rocky Linux and AlmaLinux explain the timer and the choice between downloading updates and applying dem. Update wey you install no go restart daemons wey still dey run the old code, so checking wetin still need restart or reboot worth that one minute whenever openssh-server or library wey e link with enter the batch.
FAQ
Why sshd dey fail to start after I change the port for Rocky Linux?
Almost every time, na SELinux port label dey miss. sshd dey run inside the confined sshd_t domain, and policy only allow am bind ports wey get ssh_port_t label. By default, na port 22 alone get this label. Kernel reject the bind, so daemon comot instead of listening, and journalctl -u sshd carry line wey look like error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. Run sudo semanage port -a -t ssh_port_t -p tcp 2222 with your own port number, then restart the service. If semanage no dey found, install policycoreutils-python-utils first.
I still need semanage if SELinux dey permissive mode?
Yes. For permissive mode, system record the denial but allow the bind anyway, so e go look like say the change work. But the label still dey miss. As soon as person run setenforce 1, or the box boot with SELINUX=enforcing inside /etc/selinux/config, sshd go stop starting on that port. Adding the label na one command, and e remove one failure wey fit show up weeks later without clear cause.
The port get label and sshd dey run, so why my connection dey time out?
When daemon dey run, e mean SELinux no get issue, so na on the way enter the packet dey get dropped. Check sudo firewall-cmd --list-ports for your port, and confirm say you run firewall-cmd --reload after the --permanent rule, because permanent rule by itself no reach the firewall wey dey run now. Then check your host control panel for another network firewall wey dey before the VPS. Na the second place wey people dey get blocked, and nothing inside the operating system go show am.
Which port I suppose use instead of 22?
Use any free TCP port from 1024 to 65535. For real server, avoid 2222 and 22222, because scanners dey try dem immediately after 22. Confirm say the number free with sudo ss -tlnp, confirm say SELinux policy never claim am with sudo semanage port -l, and avoid any port assigned to service wey you fit install later. High number wey no easy remember dey okay, because you go write am inside ~/.ssh/config once and you no go type am again.