Script 15 · SSH Security
15. Change SSH Port
Changes the SSH listening port, updates nftables and Fail2ban, and offers rollback if new login testing fails.
Category: SSH Security
Risk: Destructive
Lines: calculating
Language: Bash / Linux
What this script does
- Move SSH away from port 22.
- Open the new port in local firewall rules.
- Preserve a recovery path before committing changes.
Prerequisites
- Root access
- Console or existing SSH session kept open
- Provider firewall allows new port
- nftables available
Execution flow
- Backs up sshd/fail2ban/nftables
- Opens new port
- Edits sshd_config
- Restarts SSH and Fail2ban
- Prompts to commit or rollback
Validation checklist
- ss -tulpn | grep <port>
- ssh root@IP -p <port>
- nft list ruleset
Operational cautions
- Can lock you out if provider firewall blocks the new port.
- Always test a new SSH session before closing the old one.
Original script notes
ℹ️ Script Info: Safely moves the default SSH service from port 22 to a custom port of your choice, updating the firewall (NFTables) and Fail2ban configurations simultaneously to prevent unauthorized access.
⚠️ Destructive Action: Changing the SSH port may lock you out of the server if firewalls like NFTables, UFW, or your Cloud VPS provider have not allowed the new port. Always test the login in a new terminal tab before closing your current session.
cat << 'EOF' > change_ssh_port.sh
#!/bin/bash
# Output Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'
echo -e "${BLUE}=== SSH PORT & FAIL2BAN CHANGE WIZARD ===${NC}"
# 1. Ask for New Port
read -p "Enter the New SSH Port you want to use (example: 2022): " NEW_PORT
if ! [[ "$NEW_PORT" =~ ^[0-9]+$ ]] || [ "$NEW_PORT" -le 0 ] || [ "$NEW_PORT" -gt 65535 ]; then
echo -e "${RED}Error: Invalid Port.${NC}"
exit 1
fi
echo -e "\n${BLUE}[PROCESS 1/5] Backing up Configuration...${NC}"
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak_auto
if [ -f /etc/fail2ban/jail.local ]; then
cp /etc/fail2ban/jail.local /etc/fail2ban/jail.local.bak_auto
fi
# Backup current nftables rules
sudo nft list ruleset > /tmp/nftables.bak.rules
echo -e "${BLUE}[PROCESS 2/5] Opening Port $NEW_PORT in Firewall (NFTables)...${NC}"
# Add allow rule at the top to prevent blocking by other rules
sudo nft insert rule inet filter input tcp dport $NEW_PORT accept
echo "Port $NEW_PORT opened."
echo -e "${BLUE}[PROCESS 3/5] Updating SSH Configuration...${NC}"
# Change Port in sshd_config (handling #Port 22 or old Port line)
sudo sed -i "s/^#Port 22/Port $NEW_PORT/" /etc/ssh/sshd_config
sudo sed -i "s/^Port [0-9]*/Port $NEW_PORT/" /etc/ssh/sshd_config
sudo systemctl restart ssh
echo "SSH Service restarted on port $NEW_PORT."
echo -e "${BLUE}[PROCESS 4/5] Updating Fail2Ban...${NC}"
if [ -f /etc/fail2ban/jail.local ]; then
# Update port in jail.local. Assuming [sshd] block exists.
# We search for [sshd] block then replace port = ssh or port = number with new port
# Safe sed approach for standard fail2ban config
sudo sed -i "/^\[sshd\]/,/^\[/ s/^port\s*=.*/port = $NEW_PORT/" /etc/fail2ban/jail.local
sudo systemctl restart fail2ban
echo "Fail2Ban restarted with target port $NEW_PORT."
else
echo "Fail2Ban configuration file not found, skipping this stage."
fi
echo -e "${BLUE}[PROCESS 5/5] Verifying...${NC}"
sleep 2
if ss -tulpn | grep -q ":$NEW_PORT"; then
echo -e "${GREEN}SUCCESS: SSH detected running ('listening') on port $NEW_PORT.${NC}"
else
echo -e "${RED}WARNING: SSH seems to have failed running on port $NEW_PORT.${NC}"
fi
echo -e "\n-----------------------------------------------------------"
echo -e "${RED}IMPORTANT:${NC} DO NOT CLOSE THIS TERMINAL!"
echo "Open a new terminal/PuTTY, and try logging in: ssh root@IP_VPS -p $NEW_PORT"
echo "-----------------------------------------------------------"
read -p "Was the login successful and do you want to save these changes? (y/n)
[y] = Save Permanently (Apply)
[n] = Cancel & Return to Port 22 (Restore)
Your Choice: " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
echo -e "\n${GREEN}[SAVING CHANGES]${NC}"
# Save firewall permanently
sudo nft list ruleset | sudo tee /etc/nftables.conf > /dev/null
# Remove backup files
rm /etc/ssh/sshd_config.bak_auto
rm /etc/fail2ban/jail.local.bak_auto 2>/dev/null
echo "Firewall, SSH, and Fail2Ban configurations have been saved permanently."
echo -e "${GREEN}Done. Your SSH Port is now: $NEW_PORT${NC}"
else
echo -e "\n${RED}[CANCELLING CHANGES - RESTORE]${NC}"
# 1. Restore Config SSH
echo "Restoring SSH config..."
cp /etc/ssh/sshd_config.bak_auto /etc/ssh/sshd_config
# 2. Restore Config Fail2Ban
echo "Restoring Fail2Ban config..."
if [ -f /etc/fail2ban/jail.local.bak_auto ]; then
cp /etc/fail2ban/jail.local.bak_auto /etc/fail2ban/jail.local
fi
# 3. Restore Firewall (Remove new port rule)
echo "Closing port $NEW_PORT again..."
# Safest way to restore nftables to state right before script ran
sudo nft -f /tmp/nftables.bak.rules
# 4. Restart Service
echo "Restarting services to initial state..."
sudo systemctl restart ssh
sudo systemctl restart fail2ban
echo -e "${GREEN}Done. Server returned to using Port 22 (Default).${NC}"
fi
EOF
chmod +x change_ssh_port.sh && sudo ./change_ssh_port.sh