Do as many mitigations as you can.
Your goal is to force a wide variety of potential attackers to spend more effort, resources, computer time (and thus electric bill), and most especially "skilled" (rare or scarce, and thus valuable) person-hours. No one protection works against every threat. Not every threat can be protected against while still remaining on the internet.
However, a large number of threats (script kiddies and low skilled or low resourced attackers) can be defeated almost all the time by having a defense in depth - many layers of good, solid security, each of which should - theoretically - be enough to defeat many threats on its own. Thus, when your system's iptables rules let someone in by accident, the SSHD certificate authentication keeps them out. When your SSHD service has a flaw, your VPN prevents anyone from seeing it. When both your VPN and your SSHD have a flaw at the same time, your firewall rules prevent most of the world's IP addresses from even attempting it, leaving only locals and large botnets to be able to try and exploit the vulnerabilities, which you patch as soon as possible.
Thus, I say again, put in as many mitigations at as many levels as possible. You cannot know in advance which ones have undiscovered vulnerabilities, and which order those will be exploited in.
Make certain you only allow SSH v2
sshd_config
Stay patched
Use your iptables to allow ONLY the IP addresses or ranges you actually use
Set up your SSH to allow access ONLY by certificate, not by username/password, per the Ubuntu help site SSH/OpenSSH/Configuring page
sshd_config
If you use an encrypted home directory
- AuthorizedKeysFile /etc/ssh/%u/authorized_keys
If not, the normal setting for home directories can work
And set up as strong a certificate as you can. Generating keys is covered at the Ubuntu help site SSH/OpenSSH/Keys page
I'd start with a 4096 bit RSA key or an ed25519 key with a long, strong passphrase. Be sure to generate it locally, type in a long, strong passphrase when prompted, use -o to ensure the new OpenSSH 6.5 key format, and make sure the server never has anything but the public key.
ssh-keygen -o -t ed25519 -f ~/.ssh/id_ed25519
ssh-keygen -o -b 4096 -t rsa -f ~/.ssh/id_rsa
To check length on an existing key, use ssh-keygen -e -f mykeyfile
If you can, restrict keys in the authorized_keys file to a specific IP address or set of hostnames
from="192.168.1.2" ssh-rsa ABCDE...012 test@test.test
from="*.test.test,!BadPC.test.test" ssh-ed25519
ABCDE...012 test@test.test
If you're on OpenSSH 6.8 or higher, you can restrict authorized keys to certain types as well in sshd_config
- PubkeyAcceptedKeyTypes ssh-ed25519*,ssh-rsa*
Use fail2ban to make brute force attempts take more effort (i.e. make them use a botnet instead of only one machine, or make them take a lot of time)
Setting up certificates (keys) is superior if you're asking which one to do first
Reduce your login grace time
If you're using certificates, you have the option to crank it WAY down unless you use very, very slow connections
Otherwise, well, how fast do you type?
Control your cipher suite choices with information from Mozilla.org Security/Guidelines/OpenSSH
Since it's your server, and only you are getting in, you can select a very, very tight grouping such that only the most modern clients are allowed. Perhaps
HostKey /etc/ssh/ssh_host_rsa_key
- sudo ssh-keygen -o -N '' -b 4096 -t rsa -f /etc/ssh/ssh_host_rsa_key
or
HostKey /etc/ssh/ssh_host_ed25519_key
or both (most preferred first)
remove all dsa keys entirely; they're fixed at a pathetic 1024 bits for SSH
Use ssh -Q directives to determine what your system supports for the cipher suite options
KexAlgorithms curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com
Or whatever specific choices make you feel safest
- And keep up with the literature; when there's a flaw in something you've chosen, choose something that doesn't have known flaws at that point in time.
Use your iptables (or firewall) with blocklists from I-blocklist
Use your iptables (or firewall) with geographical or ISP based IP lists; one such source of geographical lists is maxmind.com
Switch to a port in the dynamic (ephemeral) port range of 49152 to 65535 per RFC6335
And only bind to the IP addresses required
Block everything other port on that server via iptables; chances are you're getting hit by a LOT of attacks
Especially harden your MySQL database, if any - I see a LOT of MySQL (and SQL Server) attacks on my IDS, and I've never run either one or had either port open. Set them to local, non-routable IP's only, etc., long passwords, disable them, etc.
Especially disable any web servers, set them to local, non-routable IP's only, etc.
Use port knocking per the Ubuntu help site or a DigitalOcean article
Rate limit new connection attempts, per this answer to ServerFault question "Hundreds of failed ssh logins"
iptables -A INPUT -p tcp --dport 22 -m recent --update --seconds 60 --hitcount 5 --name SSH --rsource -j DROP
iptables -A INPUT -p tcp --dport 22 -m recent --set --name SSH --rsource -j ACCEPT
Consider using chroot per the Debian documentation
"OpenSSH SFTP chroot() with ChrootDirectory"
Ensure rhosts is disabled with the sshd_config option
IgnoreRhosts yes
RhostsRSAAuthentication no
RhostsAuthentication no
Add more restrictions to the pre-authentication unprivileged process
UsePrivilegeSeparation sandbox
If you aren't using fowarding or tunnelling, disable it in sshd_config
X11Forwarding no
AllowTcpForwarding no
GatewayPorts no
PermitTunnel no
Prevent other insecure setup in directories or permissions
StrictModes yes
And then go through your permissions and settings until it works again :)
Disable host based authentication
HostbasedAuthentication no
Note that per This Serverfault answer to "OpenSSH daemon ignores ServerKeyBits directive", the old ServerKeyBits sshd_config directive is no longer applicable, since you don't allow SSH v1 in the first place.
Don't allow root in sshd_config
PermitRootLogin no
Don't allow different users - perhaps service users on some package you install - to have other options
PermitUserEnvironment no
Install a separate, all-up firewall like pfSense or a Ubiquiti Edgerouter Lite between that machine and the outside world.
And then use the built-in VPN IN ADDITION TO your hardened SSH login
And use the blocklists mentioned above at this level also
As DeerHunter mentioned, changing ssh and/or iptables and/or other firewall settings without any other way in can result in a lack of ability to SSH in.