I used to skip this stuff. Spin up a server, drop my app on it, done. Worked fine for months.
Then one morning I woke up to find one of my servers sending spam. Password auth was still on. Some bot had cracked it overnight.
That was the last time I skipped the setup checklist. Now I run through these steps every single time before I touch anything else — takes about 10 minutes, and it's become so automatic I barely think about it anymore.
This isn't a deep-dive security guide. It's the practical baseline: non-root user with sudo, SSH key auth, and a firewall. Everything else in this series builds on top of this foundation.
I run this on Tencent Cloud Lighthouse. A few reasons it works well for this kind of setup: OrcaTerm is a browser-based SSH terminal built into the control panel, so you can do the entire initial configuration without a local SSH client. Lighthouse also provides a console-level firewall that's completely independent of the OS — if you accidentally misconfigure UFW and lock yourself out, the console firewall keeps the server protected while you fix it. Fresh instances spin up with Ubuntu 22.04 LTS in under 2 minutes, and the snapshot feature lets you take a full server backup before making any major changes.
Key Takeaways
- Always disable root SSH login and password authentication before deploying anything
- SSH key authentication is significantly more secure than passwords
- Lighthouse has a console-level firewall independent of UFW — two layers of protection
- OrcaTerm lets you complete the entire initial setup from a browser
- Run
sudo apt update && sudo apt upgrade -ybefore installing anything
A freshly provisioned Ubuntu server has:
Bots actively scan the internet for servers with default SSH configurations. Within minutes of a server going online, it will start receiving brute-force login attempts. This isn't paranoia — it's what the logs show.
The setup below takes about 10 minutes and addresses all three issues.
From the Lighthouse console, either click OrcaTerm for a browser-based terminal, or SSH from your local machine:
ssh root@YOUR_SERVER_IP
You'll be prompted for the root password (set during instance creation, or found in the console). You're now logged in as root — which is exactly what we're going to change.
Running everything as root is risky. One typo in a command can take down the whole server. Create a regular user instead:
# Create a new user (replace "gavin" with your preferred username)
adduser gavin
You'll be prompted to set a password and fill in some optional info (just press Enter to skip the optional fields).
Grant this user sudo privileges:
usermod -aG sudo gavin
Test that it works:
# Switch to the new user
su - gavin
# Test sudo
sudo whoami
# Should output: root
Password-based SSH is vulnerable to brute-force attacks. Key-based authentication is both more secure and more convenient.
If you don't already have an SSH key pair, create one on your local computer (not the server):
# On your local machine
ssh-keygen -t ed25519 -C "your_email@example.com"
Press Enter to accept the default location (~/.ssh/id_ed25519). Set a passphrase if you want extra security.
The easiest way:
# On your local machine
ssh-copy-id gavin@YOUR_SERVER_IP
If ssh-copy-id isn't available (Windows), do it manually. On the server, while logged in as your new user:
# On the server, as your new user
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
Paste your public key (the contents of ~/.ssh/id_ed25519.pub from your local machine), save, then:
chmod 600 ~/.ssh/authorized_keys
Test that key authentication works before proceeding:
# On your local machine — should log in without asking for password
ssh gavin@YOUR_SERVER_IP
Once you've confirmed key authentication works, disable password login entirely:
sudo nano /etc/ssh/sshd_config
Find and update these lines:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
Save the file, then restart SSH:
sudo systemctl restart sshd
Important: Keep your current SSH session open while testing in a second window. If something goes wrong, you'll still have the original session to fix it.
# Test in a new terminal window
ssh gavin@YOUR_SERVER_IP
# Should connect using your key, no password prompt
UFW (Uncomplicated Firewall) is Ubuntu's front-end for iptables. The goal: deny everything by default, allow only what you need.
# Install UFW if not present
sudo apt install -y ufw
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH — do this BEFORE enabling the firewall
sudo ufw allow ssh
# Or explicitly: sudo ufw allow 22/tcp
# Allow HTTP and HTTPS (for web servers)
sudo ufw allow http
sudo ufw allow https
# Enable the firewall
sudo ufw enable
# Type "y" when prompted
# Check status
sudo ufw status verbose
The output should show your allowed ports and the default deny policy.
⚠️ Always allow SSH before enabling UFW. Locking yourself out of SSH on a remote server is a painful experience. If you do get locked out on Lighthouse, you can use OrcaTerm in the console to get back in.
Fresh Ubuntu images may have packages that were released after the image was built. Update everything:
sudo apt update && sudo apt upgrade -y
# Remove packages that are no longer needed
sudo apt autoremove -y
If the kernel was updated, you'll want to reboot:
sudo reboot
Wait about 30 seconds, then reconnect.
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Select "Yes" to enable automatic security updates
This applies security patches automatically without requiring you to log in and run updates manually.
Set the timezone to match where you or your users are located (affects log timestamps):
# List available timezones
timedatectl list-timezones | grep America
# Set your timezone
sudo timedatectl set-timezone America/New_York
# Verify
timedatectl
Give your server a meaningful hostname instead of a random string:
# Set hostname
sudo hostnamectl set-hostname my-web-server
# Update /etc/hosts to match
sudo nano /etc/hosts
# Find the line with 127.0.1.1 and update it:
# 127.0.1.1 my-web-server
# Verify
hostname
I've seen people (including myself, once) disable password authentication and then realize they hadn't properly set up key authentication first. The result: locked out of the server entirely.
The fix on Lighthouse is straightforward — use OrcaTerm in the console to get back in. But it's still a hassle.
The rule: always verify key login works in a second terminal window before disabling password auth. Don't close the original session. Don't restart SSH until you've confirmed the new session connects successfully.
Another common skip: forgetting to run sudo ufw allow ssh before enabling UFW. Same result — locked out.
Order matters:
Run through this after every new server provisioning:
# 1. Create non-root user
adduser USERNAME
usermod -aG sudo USERNAME
# 2. Copy SSH public key to new user
ssh-copy-id USERNAME@SERVER_IP
# 3. Verify key login works (test in new window)
ssh USERNAME@SERVER_IP
# 4. Disable password auth
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# 5. Configure firewall
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable
# 6. Update packages
sudo apt update && sudo apt upgrade -y
sudo apt install -y unattended-upgrades
# 7. Set timezone
sudo timedatectl set-timezone YOUR_TIMEZONE
Once you've run through this checklist, the server is ready for whatever you're deploying — a web app, a game server, a VPN, or anything else.
| What you've set up | Why it matters |
|---|---|
| Non-root user with sudo | Reduces blast radius of mistakes |
| SSH key authentication | Eliminates brute-force password attacks |
| Root login disabled | Blocks direct root SSH attempts |
| UFW firewall | Blocks all unexpected inbound connections |
| Auto security updates | Keeps the OS patched without manual work |
| Issue | Likely Cause | Fix |
|---|---|---|
| Connection refused | Service not running or wrong port | Check systemctl status SERVICE and verify firewall rules |
| Permission denied | Wrong file ownership or permissions | Check file ownership with ls -la and use chown/chmod to fix |
| 502 Bad Gateway | Backend service not running | Restart the backend service; check logs with journalctl -u SERVICE |
| SSL certificate error | Certificate expired or domain mismatch | Run sudo certbot renew and verify domain DNS points to server IP |
| Service not starting | Config error or missing dependency | Check logs with journalctl -u SERVICE -n 50 for specific error |
| Out of disk space | Logs or data accumulation | Run df -h to identify usage; clean logs or attach CBS storage |
| High memory usage | Too many processes or memory leak | Check with htop; consider upgrading instance plan if consistently high |
| Firewall blocking traffic | Port not open in UFW or Lighthouse console | Open port in Lighthouse console firewall AND sudo ufw allow PORT |
What is the first thing to do after creating a cloud server?
Disable root SSH access, create a non-root sudo user, set up SSH key auth, enable UFW, and run system updates. About 10 minutes total.
How do I connect without a local SSH client?
Use OrcaTerm — the browser-based terminal in the Lighthouse console.
What ports should be open on a new server?
At minimum: port 22 (SSH), 80 (HTTP), and 443 (HTTPS). Add others only when needed.
Why disable root SSH login?
Root is the default brute-force target. Non-root + SSH key authentication is significantly harder to compromise.
Does UFW replace the Lighthouse console firewall?
No — they complement each other. Lighthouse console firewall works at the network infrastructure level; UFW at the OS level.
Start with a solid foundation:
👉 Tencent Cloud Lighthouse — Clean Ubuntu instances, ready in minutes
👉 View current pricing and promotions
👉 Explore all active deals and offers