This is not so much a TIL, but more a TI summarized what I’ve learned from months of Kamal deployments.

I usually deploy to Debian-based servers, that’s why this note works on the premise of a Debian server.

It should be noted that I don’t frequently deploy to new servers, I’m doing it occasionally for side projects. If the frequency was higher I’d probably look at something like Ansible or Terraform for automating such a process. For my current needs, this little guide is more than enough when I need to prepare a new server.

First steps

For accessing the server I want to use an SSH key, instead of the default root login/password that often comes when renting out a server. I copy my public SSH key to the server:

ssh-copy-id -i ~/.ssh/id_ed25519.pub root@demo-server-ip

That should enable me to access the server via:

ssh root@demo-server-ip

Once there, it doesn’t hurt to immediately update all installed packages:

sudo apt-get update && sudo apt-get upgrade
sudo apt dist-upgrade

Kamal needs Docker, so I’m installing it right away, following the official guide for Debian.

Changing to a dedicated user

It’s a good idea to create a new user other than root.

First, I create a new user (replace name with desired name):

adduser deploy

All additional details can be left blank, I just make sure I store the new chosen password safely, e.g. in a password manager.

Next, the new user should be added to the sudo and the docker group:

usermod -aG sudo deploy
usermod -aG docker deploy

In a new terminal window, I copy the public SSH key for my new user as well. That should enable me to SSH into the server as the deploy user.

ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@demo-server-ip

Changing the SSH config

Before making any changes to my SSH config, I save a backup of the config, in case I need to return to the default state:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

I then change my SSH config via:

sudo nano /etc/ssh/sshd_config

The important bits to add/change:

PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin no

Before restarting the SSH service, I make sure I’m logged into the server in another terminal, in case the config causes issues. Then I restart the SSH service:

sudo systemctl restart ssh

On a sidenote, it’s possible to tail SSH logs via:

sudo journalctl -fu ssh

After this change it should still be possible to get SSH access with the deploy user’s key. It shouldn’t be possible to a) log in as the root user and b) log in with a password authentication.

Security updates

Next, I want to make sure the server stays up-to-date and receives all relevant security updates.

If not yet installed, I install unattended-upgrades:

sudo apt install unattended-upgrades

I create a file that will hold my configs (I avoid overwriting existing config files, as they may be overriden by updates):

sudo touch /etc/apt/apt.conf.d/51myunattended-upgrades

I like to use the content from this example and copy it to my config file. That makes sure that packages are kept up-to-date without manual work.

That’s all

… for now. I’m not adding stuff like UFW or Fail2Ban because my assumption is that I’m only opening ports that are supposed to be open and therefore UFW is not the right direction. Also, UFW gives kind of a false feeling of security when used together with Docker (which is the case for Kamal deployments).

Helpful resources

I obviously didn’t come up with these ideas myself. Instead I compiled what works for my needs from the following resources:

  • https://community.netcup.com/en/tutorials/first-steps-to-protect-your-linux-server-against-common-attacks
  • https://github.com/imthenachoman/How-To-Secure-A-Linux-Server
  • https://kamalmanual.com/provisioning/