Initial Server Setup on Ubuntu 16.04
Every time I spin up a new Ubuntu 16.04 VPS I catch myself doing the same dozen things from memory, and every time I forget one. So here's the checklist, written down. A fresh box arrives with only root, password login on, and nothing filtering traffic. Fifteen minutes fixes that.
You need root (or a root key) from your provider, and an SSH key pair on your workstation (ssh-keygen -t rsa -b 4096 if you don't have one).
1. Update everything
Log in as root and update first. Provider images are often weeks or months behind.
ssh root@203.0.113.10
apt-get update
apt-get -y dist-upgrade
apt-get -y autoremove
If the kernel was upgraded, reboot now. I'd rather find out the box doesn't come back before I've put any work into it.
2. Create an admin user
Don't do daily work as root. Make a personal user and add it to the sudo group.
adduser deploy
usermod -aG sudo deploy
I use adduser rather than the lower-level useradd because it creates the home directory and asks for a password. Pick a strong one even though SSH password login is about to go away; sudo still uses it.
3. Install your SSH public key
From your workstation:
ssh-copy-id deploy@203.0.113.10
If ssh-copy-id is not available (for example on Windows with PuTTY), do it manually on the server:
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys # paste the public key, one per line
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
The permissions matter: sshd silently ignores authorized_keys if the file or directory is group- or world-writable.
Now open a second terminal and check that you can log in as deploy with the key and that sudo -i works. Keep the root session open until you're sure. I once skipped this and spent an hour in a provider's web console.
4. Turn off root login and passwords
Edit /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
Then check the syntax and reload:
sshd -t
systemctl reload sshd
sshd -t prints nothing when the config is valid. The reload doesn't drop existing sessions, so your safety-net root shell stays alive.
5. Firewall
Ubuntu ships ufw, a front end to iptables. Allow SSH before enabling it, or you'll lock yourself out.
ufw allow OpenSSH
ufw default deny incoming
ufw default allow outgoing
ufw enable
Add web ports only if this machine serves HTTP:
ufw allow 80/tcp
ufw allow 443/tcp
ufw status verbose shows the resulting rule set.
6. Hostname and timezone
Small things, but they make logs readable and prompts distinguishable when you have six terminals open.
hostnamectl set-hostname web01
timedatectl set-timezone Asia/Seoul
Add the hostname to /etc/hosts as well (127.0.1.1 web01) so sudo does not complain about being unable to resolve it.
Did it work?
From your workstation:
ssh root@203.0.113.10 # should fail: Permission denied (publickey)
ssh deploy@203.0.113.10 sudo ufw status
ssh deploy@203.0.113.10 'grep -E "^(PermitRootLogin|PasswordAuthentication)" /etc/ssh/sshd_config'
The first should be refused, the second should show Status: active with the OpenSSH rule, and the third should print the two no lines.
Things that bit me
Permission denied (publickey)for the new user is usually bad ownership or modes on~/.sshorauthorized_keys.journalctl -u sshsaysAuthentication refused: bad ownership or modes for directory /home/deploy.sudo: unable to resolve host web01means you changed the hostname without touching/etc/hosts. Harmless but noisy; add the127.0.1.1line.ufw enablehanging over SSH means you forgotufw allow OpenSSH. Most providers' web consoles let you runufw disableto recover.dist-upgradeasking about a modifiedsshd_configor grub config is normal on provider images. I keep the local version unless I know why the package one is better.
That's my baseline. Everything else on this blog assumes a machine that went through it.