Securing a New Linux Server
First-pass hardening on a fresh DigitalOcean Droplet: non-root user, SSH port, key-only login.
~/posts/securing-new-linux-server $ cat post.md
Overview
When standing up a new server, do a baseline pass: create a non-root user, change the SSH port, disable password login, and so on. This walks through the steps using a DigitalOcean Droplet as the example.
Log in
Start by SSH-ing in. DigitalOcean emails you the initial root password when the Droplet is created. After login, it forces a password change; make it as strong as you can since you won’t be using root much afterwards.
Create a non-root user
addgroup manager
useradd -d /home/deploy -s /bin/bash -m deploy
passwd deploy
usermod -a -G manager deploy
This creates the manager group, adds a deploy user under it, sets
their password, and puts them in the group. deploy is just an
example name — use whatever you’ll remember. All later service
deployment runs as this non-root user.
visudo
This opens /etc/sudoers in nano by default. Under the line root ALL=(ALL:ALL) ALL add:
deploy ALL=(ALL) NOPASSWD: ALL
Now deploy won’t be prompted for a password on sudo. If you’d
prefer to require one, use deploy ALL=(ALL:ALL) ALL instead.
For reference, the resulting sudoers on a default DigitalOcean image looks roughly like:
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root ALL=(ALL:ALL) ALL
deploy ALL=(ALL) NOPASSWD: ALL # <== add this
# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL
# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
Once that’s saved, log out and log back in as deploy:
exit
ssh deploy@<your-ip>
SSH hardening
The ideal end state is to disable SSH password login entirely and rely on keys. That’s a meaningful security gain, but losing the only machine with your key can be painful, so there are two recipes below. For production, use option one.
Option 1: disable password login
Generate a key locally and push the public half to the server:
ssh-keygen
ssh-copy-id user@host
On the server, back up and edit sshd_config:
sudo cp /etc/ssh/sshd_config ~
sudo nano /etc/ssh/sshd_config
The DigitalOcean default looks roughly like this — annotated lines are the ones to change:
# Package generated configuration file
# See the sshd_config(5) manpage for details
# What ports, IPs and protocols we listen for
Port 22 # ==> change
# Use these options to restrict which interfaces/protocols sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes
# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 1024
# Logging
SyslogFacility AUTH
LogLevel INFO
# Authentication:
LoginGraceTime 120
PermitRootLogin yes # ==> set to no
StrictModes yes
RSAAuthentication yes # ==> keep yes
PubkeyAuthentication yes # ==> keep yes
#AuthorizedKeysFile %h/.ssh/authorized_keys # ==> uncomment
# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes
# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no # ==> keep no
# Change to yes to enable challenge-response passwords
ChallengeResponseAuthentication no
# Change to no to disable tunnelled clear text passwords
PasswordAuthentication yes # ==> set to no
# ... rest omitted
UsePAM yes
UseDNS no # ==> add
AllowUsers deploy # ==> add
Summary of edits:
- Change the port to something in
> 1024and<= 65535— I tend to use something like 35245. PermitRootLogin no.PermitEmptyPasswords no.PasswordAuthentication no.UseDNS no.RSAAuthentication yes.PubkeyAuthentication yes.AuthorizedKeysFile .ssh/authorized_keys.- Add
AllowUsers deploy.
The list above covers what you’d need on a stock image; DigitalOcean already does some of these by default.
Restart sshd:
sudo service ssh restart # whichever works
sudo /etc/init.d/ssh restart # whichever works
On your laptop, add a stanza to ~/.ssh/config:
Host my-server
HostName <your-ip>
User deploy
Port <your-port>
After that, ssh my-server is enough.
Option 2: keep password login
The security gap here vs option 1 is real. Weigh it.
Same sshd_config template, but only change three things:
- Port (as above).
PermitRootLogin no.- Add
AllowUsers deploy.