I’ve been doing this more than I had expected, which warrants a blog post.

I’m on Windows, so Ansible isn’t really doable.

Securing the server

There’s no 100% security, this is just making attacks harder.

As root

My provider installs AlmaLinux 8 with a custom setup script that I don’t have.

There is no external firewall.

Log in as root:

1
ssh root@my_ip

Change the root password:

1
passwd

Create a new user and allow sudo:

1
2
3
adduser dummy
passwd dummy
usermod -aG wheel dummy

Start a firewall:

1
2
3
dnf install firewalld -y
systemctl start firewalld
systemctl status firewalld

I got a warning to disable AllowZoneDrifting, so I did:

1
2
nano /etc/firewalld/firewalld.conf
systemctl restart firewalld

Turn passwords and root login off

Edit the SSH config:

1
nano /etc/ssh/sshd_config

Note on SSH ports: I used to change SSH ports, but decided against it after reading this question. But this link tells you how to.

Turn off root login (before-after):

1
2
# PermitRootLogin yes
PermitRootLogin no

Turn off password authentication:

1
2
# PasswordAuthentication yes
PasswordAuthentication no

For some reason GSS-API was on, so I turned it off:

1
2
# GSSAPIAuthentication yes
GSSAPIAuthentication no

As user

Before restarting sshd, login to another session and copy your public keys:

1
2
3
4
su - dummy
cd
mkdir .ssh
nano ~/.ssh/authorized_keys

Set the correct permissions:

1
2
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Login to yet another session to verify that you can login.

Now’s a good time to try sudo:

1
sudo systemctl restart sshd

Then, verify that:

  • you can only login to dummy with your SSH key.
  • you cannot login with ssh dummy@my_ip
  • you cannot login with ssh root@my_ip

I then installed oh-my-bash:

1
2
sudo yum install -y git
bash -c "$(curl -fsSL https://raw.githubusercontent.com/ohmybash/oh-my-bash/master/tools/install.sh)"

For my .bashrc:

1
2
3
OSH_THEME="half-life"
DISABLE_AUTO_UPDATE="true"
export EDITOR="nano"

Docker

I considered using Podman, but my apps use docker-compose so I don’t want to worry about feature parity. I’m also not running Docker in Rootless mode for the same reasons.

Install Docker:

1
2
3
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Start Docker:

1
sudo systemctl enable --now docker

To skip sudo when using Docker:

1
2
sudo groupadd docker
sudo usermod -aG docker $USER

Then log out and log back in.

Lazydocker

Life is short, so I install lazydocker.

Change the install script so it installs in /usr/local/bin:

1
DIR="${DIR:-"/usr/local/bin"}"

Then I execute the script:

1
sudo bash install-lazydocker.sh

Apps

Add a user for qBittorrent to download Ubuntu torrents, and add myself to the group to access files:

1
2
sudo adduser qbit
sudo usermod -a -G qbit dummy

Login to a new session and check your groups with groups.

Then, I can copy my docker-compose files over and do:

1
docker compose up -d

Backup

For my own reference:

  1. Stop all containers.
  2. Delete all large files.
  3. Copy and paste ~/docker-compose and /home/qbit.
  4. For /home/qbit, do sudo chmod 770 /home/qbit.
  5. After copying, do sudo chown -R qbit:qbit qbit/.
  6. Everything should work now.

Cloudflare

My apps are not exposed to the Internet; rather, traffic is forwarded through Cloudflare.

Create a tunnel:

  • Log in to Cloudflare One.
  • In Networks > Tunnels, Create a Tunnel
  • Select Cloudflared
  • Choose a name
  • Run the “Install and run a connector” command

To add apps:

  • Click on the newly created tunnel, select “Edit”.
  • In “Public Hostname”, select “Add a public hostname”.
    • Subdomain: the subdomain you would like to put the app in.
    • Domain: one of your Cloudflare domains
    • Path: leave empty
    • Type: usually HTTP.
    • URL: usually localhost:[PORT].
  • Add the app under Access - Applications.
    • Choose “Self-hosted”.
    • Use the same subdomain, domain and path as the previous step.

Note: although the connections come into 127.0.0.1, the apps run inside Docker, so those come through whichever IPs Docker assign. This seems to be 172.18.0.0/24?

https://www.digitalocean.com/community/tutorials/initial-server-setup-with-centos

https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys-on-centos

https://docs.docker.com/engine/install/rhel/

https://docs.docker.com/engine/install/linux-postinstall/