Based on Debian 11 "Bullseye" environment.

ssh and security

To access from the remote, install an ssh server with security configurations.

ssh server

Physically accessing the server every time is not a usual solution. Normally we access the server via ssh connection from the other terminals.
As the first step, install the ssh server.


Log in as root, then install ssh.

# apt install ssh

The system will ask you to install much more than the package ssh, according to the dependency. Just answer “y” to proceed. This dependency control always happens and you don’t have to care about it most of the time.

That’s all for now. Log out from the server and set up ssh client on your everyday-task PC to access from it.

Access from the usual terminal

Set up an ssh client on the computer you mainly use.
(Please search for a suitable client for your environment. For example, PuTTY is one of the most famous clients. If you use a Japanese environment, I recommend RLogin.)

Setting the public key

If your desktop environment is Linux, it’s easy to generate the key pair. On Windows, this command should work on the command prompt. (Maybe you need WSL enabled. Please refer to the other sites for details.)

$ ssh-keygen -t ed25519

This will generate the “ed25519” private key and public key pair. Anyhow please make your own public key according to your environment.

After logging in to the server, store your public key to ~/.ssh/authorized_keys on the server-side.

$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ vi ~/.ssh/authorized_keys
~~ Copy & Paste your public key (ed25519 is a short key and easy to copy & paste) ~~
$ chmod 600 ~/.ssh/authorized_keys

“vi” is a text editor, but you can do nothing without learning the basics (once you open the file, you can’t even exit the application). If you don’t have time, probably “nano” will be the better alternative for the start.

After you store the public key to the ~/.ssh/authorized_keys, log out and try to login again with the public key authentication. (If you successfully log in with the key, the server will not ask you the password to log in.)

If you confirmed you can log in with the keys, begin the security configuration.

ssh server configuration

Get root privilege

To get the root privilege, use “su” command with the option “-“.

$ su -
Password: <input root password>


Configure /etc/ssh/sshd_config file to prohibit password login.

#PermitRootLogin prohibit-password <- Set this to "no" if you like

* snip *

# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes <- Uncomment the line and set to "no" as shown in next line
PasswordAuthentication no
#PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no <- Make sure this is already set to "no"

After you change the lines, restart the ssh server.

# systemctl restart ssh


Debian has been using nftables from Buster. On top of it, firewalld is recommended.
You may have used UFW (me too), but UFW has issues when using docker images. (See details for docker documents.)


# apt install firewalld

The ssh services (and dhcpv6-client) are registered by default, so you won't be kicked out of the server after the installation.


Since you only have ssh server to be accessed from the outside, you don't need any further configuration.
For the later manipulations, here are some basics.

Preset services

There are preset rules that can be enabled easily. You can find them in /usr/lib/firewalld/services directory.
For example, ssh.xml opens tcp:22.

<?xml version="1.0" encoding="utf-8"?>
  <description>Secure Shell (SSH) is a protocol for logging into and executing commands on remote machines. It provides secure encrypted communications. If you plan on accessing your machine remotely via SSH over a firewalled interface, enable this option. You need the openssh-server package installed for this option to be useful.</description>
  <port protocol="tcp" port="22"/>

There is a command to list all services, but it's very difficult to find one. Too many services are listed in one line.

# firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc bittorrent-lsd ceph ceph-mon cfengine cockpit collectd condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns dns-over-tls docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger foreman foreman-proxy freeipa-4 freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git grafana gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kdeconnect kerberos kibana klogin kpasswd kprop kshell kube-apiserver ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nbd nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy prometheus proxy-dhcp ptp pulseaudio puppetmaster quassel radius rdp redis redis-sentinel rpc-bind rquotad rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync spotify-sync squid ssdp ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tentacle tftp tftp-client tile38 tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server

Opening ports using preset services

Pick up the service you want to use and enable it. For example, HTTP (webserver).

# firewall-cmd --add-service=http --zone=public --permanent
# firewall-cmd --reload
  • The application name is "firewalld" (firewall + d), but command is "firewall-cmd" without "d" after the firewall.
  • "--permanent" is required to set the rules preserved after the firewall reload. Without this parameter, you can test the temporary rules.
  • "--zone-public" can be omitted because "public" is the default zone.
  • Reload required to enable the new configurations.

Disabling services

Remove the service you enabled.

# firewall-cmd --remove-service=http --zone=public --permanent
# firewall-cmd --reload

Other patterns

If what you want is not on the preset, you can manually set up the allowed port and tcp/udp. If you need this kind of custom or rules for the outbound traffic, you have other command options to set up. Please refer to the other sites for more details.




Now port 22 on the server is open and ssh service is running behind it. You will soon get malicious login attempts to kick out.
"fail2ban" will find such attempts from the ssh log file and ban that IP.

# apt install fail2ban

Second level jail

It works nicely with SSH port(22) by default.
Additionally, there is a 'recidive' preset for the continuous attacker. If the attacks continue even after the temporary ban, the ban period will be extended to 1 week.
Add a file /etc/fail2ban/jail.d/recidive.conf to enable it.

enabled = true

Then restart fail2ban.

# systemctl restart fail2ban

fail2ban can watch other logs for other ports and services. Please refer to the manual to find out more.


Always using the root account is not recommended. "sudo" command is used to delegate the privilege to a specific user.

# apt install sudo
# adduser username sudo

Adding a user to the group “sudo” will allow that user to use this command.

  • If you want to be more restrictive, you can limit the commands available to that user.
  • After adding a user to the sudo group, that user has to re-login to enable it.

Update History


  • Add recidive explanation to fail2ban
  • Remove "banaction = ufw" configuration
    Recidive doesn't work with ufw, and fail2ban doesn't have to use ufw even if ufw is installed.


  • Update the contents according to Bullseye
  • Remove UFW section
  • Add firewalld section instead of UFW