Ubuntu Server Initialization: User Management, SSH Hardening, and fail2ban Security Setup
Introduction
At 3 AM, I stared at the “Permission denied” error in my terminal, cold sweat running down my back.
I was locked out of my server. All because I casually changed an SSH configuration without leaving myself a backup plan.
That was three years ago when I bought my first VPS. Looking back now, my approach was a textbook example of what NOT to do: logging in directly as root, setting my birthday as the password, using the default SSH port 22, and firewall? Never heard of it. The result? My server got hammered within two weeks, with brute force attack traces all over the logs.
Let’s be honest—many beginners’ first instinct after buying a VPS is to start installing software and deploying projects immediately. User management? SSH hardening? Too much hassle, let’s deal with that later. But those “later” tasks are exactly what determine how long your server survives.
This article does one thing: walk you through configuring a fresh Ubuntu server (22.04 or 24.04) from scratch into a secure, production-ready state. User permissions, SSH hardening, fail2ban auto-banning—we’ll cover everything. At each step, I’ll explain why we’re doing it, not just give you a pile of commands to copy-paste.
About 10 minutes to complete this entire flow. After that, your server’s security level will exceed 80% of the exposed machines on the internet.
1. Pre-Initialization Preparation
Before we start, let’s get our tools ready. You’ll need to generate an SSH key pair locally.
Why keys instead of passwords? Simply put, passwords can be brute-forced; keys essentially cannot. A 256-bit Ed25519 key would take longer to crack than the age of the universe.
Key Generation
These days, I recommend Ed25519 over the older RSA—it’s more secure and produces shorter keys. The generation command is straightforward:
# macOS / Linux
ssh-keygen -t ed25519 -C "your_email@example.com"
# Windows (PowerShell, requires OpenSSH client)
ssh-keygen -t ed25519 -C "your_email@example.com"
After running it, you’ll be asked where to store the key and whether to set a passphrase. Press Enter to use the default path. Whether to add a passphrase is up to you—it’s more secure if you do, but you’ll need to enter it every time you connect.
After generation, you’ll have two files locally:
~/.ssh/id_ed25519— Private key, NEVER share this~/.ssh/id_ed25519.pub— Public key, this will be uploaded to the server
For terminal tools, macOS’s built-in Terminal works fine. Windows users might prefer Windows Terminal or MobaXterm. Not the focus here, so I won’t elaborate.
2. User and Permission Management
First, log into your server as root (this is the last time you’ll log in directly as root—we’ll disable it afterward):
ssh root@your_server_ip
Why Not Use root?
In short: the consequences are too severe.
Root has too much power—delete one wrong file, change one wrong configuration, and your entire system is toast. Worse, many attack scripts specifically target the root account for brute force attacks. Exposing root in SSH login is like handing hackers a giant target.
Use a regular account for daily operations, and sudo when you need elevated privileges. This is a fundamental Linux security principle.
Create a Deployment User
I like to use the name deploy, meaning “for deployment purposes.” You can use any name you prefer:
# Create user (will prompt for password and some info)
adduser deploy
# Grant sudo privileges
usermod -aG sudo deploy
Ubuntu will ask you to set a password and fill in user information. Set a memorable password; for the other fields, just press Enter to skip.
Upload Public Key to New User
Now upload your local public key to this new account. Run this on your local machine:
# macOS / Linux
ssh-copy-id deploy@your_server_ip
# Windows (PowerShell)
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh deploy@your_server_ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Then test if you can log in as deploy:
ssh deploy@your_server_ip
Logged in successfully? Great. From now on, operate as deploy—don’t switch back to root. Need root privileges? Just add sudo.
Multi-User Scenario
If your server needs to be shared by a team, you can create separate accounts for each person. For example:
# Create account for colleague John
adduser john
usermod -aG sudo john
# Have them upload their public key (they run this locally)
ssh-copy-id john@your_server_ip
Everyone uses their own account—operation logs are traceable, and it’s easier to troubleshoot when issues arise.
3. SSH Security Hardening
This is the most critical part of initialization, and also where “locking yourself out” disasters most commonly occur.
Warning: Before changing SSH configuration, always keep your current connection open while testing in a separate terminal window. This way, if something goes wrong, you can fix it from the other window.
Edit SSH Configuration File
sudo nano /etc/ssh/sshd_config
Line-by-Line Explanation of Core Parameters
1. Port
Port 22 # Default value, should be changed
Port 22 is the primary target for internet-wide scans. Changing to a high port (like 22222 or 54321) avoids most indiscriminate scanning.
Port 54321
Note: If you’re using a cloud provider (Alibaba Cloud, Tencent Cloud, AWS, etc.), remember to open the new port in your security group/firewall after changing, or you won’t be able to connect.
2. PermitRootLogin
PermitRootLogin no # Must change
Why? I mentioned it earlier—root is hackers’ number one target. Disable it, and your attack surface shrinks significantly.
3. PasswordAuthentication
PasswordAuthentication no # Key-based login only
This is critical for preventing brute force attacks. As long as your private key doesn’t leak, even if someone knows the password, they can’t get in.
4. Other Security Parameters
MaxAuthTries 3 # Maximum 3 password attempts
ClientAliveInterval 300 # Disconnect after 5 minutes of inactivity
ClientAliveCountMax 2 # Maximum 2 unresponsive checks
These parameters prevent idle connections from hogging resources and limit brute force attempts.
Three-Step Configuration Verification
Don’t rush to restart after changing configuration—verify first:
Step 1: Test Configuration Syntax
sudo sshd -t
No output is good news—syntax is fine.
Step 2: Test Connection in New Window
Keep your current window open. Open another terminal window and connect with the new port and deploy account:
ssh -p 54321 deploy@your_server_ip
Can connect? Configuration is working, and you haven’t locked yourself out.
Step 3: Restart Service After Confirmation
sudo systemctl restart sshd
# or
sudo systemctl restart ssh
After restarting, test once more in a new window. Confirm you can log in normally—only then is this step truly complete.
Pro Tip
If you find yourself locked out after changing configuration, don’t panic. Go to your cloud provider’s console, use VNC login, revert the configuration, and restart the service. That’s why I keep emphasizing—maintain one connection before changing SSH configuration.
4. fail2ban Auto-Banning
The SSH configuration we discussed mainly prevents brute force attacks. But what if someone keeps trying passwords relentlessly? That’s where fail2ban comes in.
What is fail2ban? A tool that automatically monitors logs and bans suspicious IPs. Someone fails password attempts a few times in a row? Automatically banned for a period. Simple, brutal, and effective.
Installation and Startup
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Configure SSH Jail
fail2ban uses the concept of “jails” to manage monitoring rules for different services. SSH has a default sshd jail.
Create a local configuration file (don’t modify the default configuration directly—upgrades will overwrite it):
sudo nano /etc/fail2ban/jail.local
Add the following content:
[sshd]
enabled = true
port = 54321 # Change to your SSH port
maxretry = 3 # Ban after 3 failures
findtime = 600 # Within 10 minutes
bantime = 3600 # Ban for 1 hour
Parameter Explanation:
maxretry: Maximum allowed failures. Default is 5; I changed it to 3 for stricter security.findtime: Time window in seconds. 600 seconds = within 10 minutes, 3 failures trigger action.bantime: Ban duration in seconds. 3600 = 1 hour. You can set it to 86400 (one day) or longer.
Restart the service after changes:
sudo systemctl restart fail2ban
Check Ban Status
# Check all jail statuses
sudo fail2ban-client status
# Check sshd jail details
sudo fail2ban-client status sshd
You’ll see a list of currently banned IPs.
Unban IP
If you accidentally ban yourself (e.g., entering wrong password too many times during debugging), unban like this:
sudo fail2ban-client set sshd unbanip your_ip
Advanced: Custom Rules
fail2ban can protect more than just SSH—it can also protect Nginx, Apache, MySQL, and other services. Configuration is similar: create corresponding jails. This topic runs deep, so I’ll just mention it here.
5. Version Differences Quick Reference
Ubuntu 22.04 and 24.04 have largely identical initialization processes, but some details differ.
Core Differences Comparison
| Item | Ubuntu 22.04 LTS | Ubuntu 24.04 LTS |
|---|---|---|
| Kernel Version | 5.15 | 6.8 |
| OpenSSH Version | 8.9 | 9.6 |
| Default Python | 3.10 | 3.12 |
| systemd Version | 249 | 255 |
| Support Cycle | Until April 2027 | Until April 2029 |
Practical Impact
Good news: The initialization process in this article works identically on both versions. SSH configuration paths, fail2ban installation methods, and user management commands haven’t changed.
Points to note:
-
OpenSSH 9.x (24.04) has stricter default configurations, with some older encryption algorithms disabled. If you’re using an older SSH client to connect to 24.04, you might encounter issues—just upgrade the client.
-
Cloud provider images: Some cloud providers’ 22.04 images come pre-installed with monitoring or management scripts that might conflict with your configuration. I recommend using official clean images or checking existing services before initialization.
-
Upgrade issues: If you have a running 22.04 server, make a snapshot before upgrading to 24.04. While
do-release-upgradesucceeds most of the time, it’s better to be safe with security configurations.
Which to Choose?
- New projects: Go with 24.04. Longer support cycle, newer software versions.
- Legacy projects: If you depend on specific versions (like Python 3.10), use 22.04.
- Stability priority: 22.04 is mature; most pitfalls have been discovered.
- Trying new things: 24.04 has new features like better hardware support and performance optimizations.
Summary
After all that, let’s review the core points of this initialization process:
Security Trio:
- Create regular user, disable root login
- Change SSH port, disable password login, allow key-based only
- fail2ban auto-bans suspicious IPs
Operational Principles:
- Keep one connection open before changing configurations
- Verify each step, don’t rush to restart
- Private key must NEVER leak
Verification Checklist:
- Can SSH login with deploy account through new port
- root account cannot login
- Password login disabled
- fail2ban service running normally
This configuration is just the first step in server security. Next, you’ll need to configure firewall (UFW), install Docker, deploy applications… topics for another day.
If you run into issues following this tutorial, feel free to leave a comment. That 3 AM lockout disaster three years ago—I genuinely don’t want you to experience it.
Ubuntu Server Initialization Security Configuration
Configure a secure Ubuntu server from scratch, including user management, SSH hardening, and fail2ban banning
⏱️ Estimated time: 10 min
- 1
Step1: Generate SSH Key
Generate an Ed25519 key pair on your local machine:
• Command: ssh-keygen -t ed25519 -C "email@example.com"
• Private key stored in ~/.ssh/id_ed25519 (never share)
• Public key stored in ~/.ssh/id_ed25519.pub (to be uploaded) - 2
Step2: Create Regular User
After logging into the server, create a deployment user:
• Create user: adduser deploy
• Grant sudo privileges: usermod -aG sudo deploy
• Set a memorable password - 3
Step3: Upload Public Key and Test Login
Run on your local machine:
• ssh-copy-id deploy@server_ip
• Test login: ssh deploy@server_ip
• Confirm you can login as deploy normally, then use this account for subsequent operations - 4
Step4: Modify SSH Configuration
Edit /etc/ssh/sshd_config:
• Port 54321 (change to high port)
• PermitRootLogin no (disable root login)
• PasswordAuthentication no (disable password login)
• MaxAuthTries 3
• ClientAliveInterval 300
Note: Keep one connection open before modifying! - 5
Step5: Verify and Restart SSH
Three-step verification:
• Test syntax: sudo sshd -t
• Test in new window: ssh -p 54321 deploy@server_ip
• Restart after confirmation: sudo systemctl restart sshd - 6
Step6: Install and Configure fail2ban
Auto-ban brute force IPs:
• Install: sudo apt install fail2ban -y
• Configure /etc/fail2ban/jail.local
• Set maxretry=3, bantime=3600
• Restart service: sudo systemctl restart fail2ban
FAQ
What SSH port should I use?
What if I can't connect after changing SSH configuration?
Can fail2ban ban my own IP?
What's the difference between Ubuntu 22.04 and 24.04 initialization?
How much more secure is key-based login compared to password login?
Can I change the SSH port back to 22?
10 min read · Published on: Mar 27, 2026 · Modified on: Mar 27, 2026
Related Posts
Building Admin Skeleton with shadcn/ui: Sidebar + Layout Best Practices
Building Admin Skeleton with shadcn/ui: Sidebar + Layout Best Practices
Tailwind Responsive Layout in Practice: Container Queries and Breakpoint Strategies
Tailwind Responsive Layout in Practice: Container Queries and Breakpoint Strategies
What is shadcn/ui? How to Choose Between MUI, Chakra, and Ant Design

Comments
Sign in with GitHub to leave a comment