๐ SSH Keys โ How They Work
SSH keys let you log into remote servers without a password. Each machine has its own key pair:
- Private key โ stays on the machine (never share this)
- Public key (.pub) โ gets copied to servers you want to access
A key only works for the specific user it's been added to. For example:
- Key added to
/root/.ssh/authorized_keys โ can log in as root
- Key added to
/home/philcoates/.ssh/authorized_keys โ can log in as philcoates
๐ก The Mac Pro has its own key at /Users/macpro/.ssh/id_ed25519. Your laptop has a separate key. Both need to be deployed to servers you want to access from each machine.
๐ Generating a New SSH Key
Run this on the machine that needs the key (e.g. your laptop):
ssh-keygen -t ed25519
Press Enter for defaults. Your key pair will be at:
- Private:
~/.ssh/id_ed25519
- Public:
~/.ssh/id_ed25519.pub
View your public key:
cat ~/.ssh/id_ed25519.pub
๐ Deploying Keys to Servers
Via the Admin Panel (Mac Pro's key)
Go to Managed Servers โ click ๐ Push Key on a server. Enter the server password. This deploys the Mac Pro's key to root and your configured additional user.
Via the Admin Panel (your laptop's key)
Go to SSH Keys โ click + Add SSH Key. Paste your laptop's public key. Then click ๐ Sync All Keys to push it to all managed servers.
Via command line
ssh-copy-id philcoates@server.com
ssh-copy-id -p 60437 philcoates@server.com
ssh-copy-id -p 60437 root@server.com
Manually (if root login is disabled)
ssh -p 60437 philcoates@server.com
sudo mkdir -p /root/.ssh
sudo cp ~/.ssh/authorized_keys /root/.ssh/authorized_keys
sudo chmod 700 /root/.ssh
sudo chmod 600 /root/.ssh/authorized_keys
๐ Connecting to Servers
ssh philcoates@server.com
ssh -p 60437 philcoates@server.com
ssh -p 60437 root@149.102.131.105
sudo su -
SSH Config (avoid typing port every time)
Add to ~/.ssh/config:
Host filemaker
HostName filemaker.fmhosting.uk
User philcoates
Port 60437
Host henderson
HostName henderson.fmhosting.uk
User philcoates
Port 22
Then just:
ssh filemaker
ssh henderson
๐ฅ๏ธ Setting Up a New Server
Full workflow for a fresh Contabo server:
- Add the server in Managed Servers โ + Add Server
- Click ๐ Push Key โ enter the initial root password
- Click ๐ Test to verify SSH key access works
- Add your laptop's key in SSH Keys and Sync All Keys
- Click ๐ Apply Hardening โ tick Zabbix/RustDesk if needed
- Set up the backup job in + Add Backup Job
- Create a client access code if the client needs download access
โ ๏ธ Before hardening, make sure the SSH key works! Hardening disables password auth โ if your key isn't deployed, you'll be locked out.
๐ค Adding a New User to a Server
ssh -p 60437 root@server.com
adduser philcoates
echo "philcoates ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/philcoates
chmod 440 /etc/sudoers.d/philcoates
mkdir -p /home/philcoates/.ssh
cp /root/.ssh/authorized_keys /home/philcoates/.ssh/
chown -R philcoates:philcoates /home/philcoates/.ssh
chmod 700 /home/philcoates/.ssh
chmod 600 /home/philcoates/.ssh/authorized_keys
๐ก Set the additional username in Settings โ Additional SSH Deploy Username so Push Key deploys to both root and this user automatically.
๐ Security Hardening
The hardening script applies these protections:
- SSH โ disables password auth, limits auth tries to 3, disables X11/agent forwarding
- Fail2ban โ 2 SSH failures = 24hr ban, repeat offenders get permanent ban
- UFW โ denies all incoming except SSH, HTTP/S, FileMaker ports
- Auto-updates โ security patches applied automatically (no auto-reboot)
- Kernel โ SYN cookies, reverse path filtering, shared memory hardening
- Services โ disables FTP, Avahi, CUPS, Bluetooth, RPC
Optional firewall ports (checkboxes in the hardening dialog):
- Zabbix โ ports 10050, 10051
- RustDesk โ ports 21115-21119 TCP, 21116 UDP
๐ก The script auto-detects the SSH port from the server config, and only adds FileMaker jails if FMS is installed.
โ ๏ธ Non-root users (e.g. philcoates) need passwordless sudo for hardening to work. Check with: sudo -n whoami
๐ Fail2ban Management
sudo systemctl status fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
sudo fail2ban-client status fms-admin
sudo fail2ban-client set sshd unbanip 1.2.3.4
sudo fail2ban-client set sshd banip 1.2.3.4
sudo fail2ban-client status sshd | grep "Banned IP"
sudo systemctl restart fail2ban
sudo tail -50 /var/log/fail2ban.log
โ ๏ธ If fail2ban won't start, check: sudo fail2ban-client -t โ usually a bad jail config or missing log file.
๐ก๏ธ UFW Firewall
sudo ufw status verbose
sudo ufw enable
sudo ufw disable
sudo ufw allow 10050/tcp
sudo ufw allow 21115:21119/tcp
sudo ufw allow from 149.22.74.121
sudo ufw status numbered
sudo ufw delete 5
sudo ufw reset
๐ฅ Backup Downloads
How downloads work in the admin panel and client portal:
- Single files (any size) โ stream immediately via Safari's download manager
- Folders under 1 GB โ zipped on-the-fly and streamed
- Folders over 1 GB โ ZIP created in background, download link emailed when ready (valid 12 hours)
Temp ZIPs are stored in rsync-gui/temp-downloads/ and auto-cleaned after 12 hours.
๐ก Caddy reverse proxy has flush_interval -1 set to enable streaming. Without this, large downloads buffer and appear to hang.
๐๏ธ FMS Backup Requests
Clients can request a fresh FileMaker Server backup from the download portal. Configure per client code:
- Enable FMS backup in the client code settings
- Set the FMS host, SSH credentials, and FMS admin credentials
- Optionally link an rsync job to auto-pull after FMS backup completes
1-hour cooldown between requests. All events logged to audit trail.
๐ง Maintenance
App service (Mac Pro)
launchctl unload ~/Library/LaunchAgents/com.rsync-gui.plist
launchctl load ~/Library/LaunchAgents/com.rsync-gui.plist
launchctl list | grep rsync
tail -f /Users/macpro/Shared/files/rsync-gui/logs/output.log
tail -f /Users/macpro/Shared/files/rsync-gui/logs/error.log
Caddy reverse proxy (Mac Pro)
/usr/local/etc/Caddyfile
sudo caddy reload --config /usr/local/etc/Caddyfile
Database maintenance
In Settings โ ๐ง Maintenance:
- Trim Outputs โ shrinks oversized run logs (caps at 50KB each)
- Prune Expired Runs โ deletes old run history beyond retention period
Both run automatically on startup and daily.
View hardening log on a server
sudo cat /var/log/server-hardening.log
๐ Troubleshooting
Locked out of a server
Use Contabo VNC console to log in, then:
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config.d/*.conf
sudo systemctl restart ssh
Fail2ban won't start
sudo fail2ban-client -t
sudo journalctl -u fail2ban --no-pager -n 30
sudo rm -f /etc/fail2ban/jail.d/fms-admin.conf
sudo systemctl restart fail2ban
UFW not active after hardening
sudo ufw enable
Downloads not working
Check Caddy has flush_interval -1 in both reverse_proxy blocks:
cat /usr/local/etc/Caddyfile
Permission denied on hardening
The user needs passwordless sudo:
echo "philcoates ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/philcoates
sudo chmod 440 /etc/sudoers.d/philcoates
Banned yourself with fail2ban
Use Contabo VNC, or from another server:
sudo fail2ban-client set sshd unbanip YOUR_IP
๐ Key File Paths
Mac Pro (app server)
App: /Users/macpro/Shared/files/rsync-gui/
Data: /Users/macpro/Shared/files/rsync-gui/data.json
Logs: /Users/macpro/Shared/files/rsync-gui/logs/
Temp downloads: /Users/macpro/Shared/files/rsync-gui/temp-downloads/
Mac Pro SSH key: /Users/macpro/.ssh/id_ed25519
Caddy config: /usr/local/etc/Caddyfile
LaunchAgent: ~/Library/LaunchAgents/com.rsync-gui.plist
Remote servers
Hardening log: /var/log/server-hardening.log
Fail2ban config: /etc/fail2ban/jail.local
Fail2ban log: /var/log/fail2ban.log
UFW rules: sudo ufw status numbered
SSH config: /etc/ssh/sshd_config
FMS logs symlink: /opt/fms-logs โ /opt/FileMaker/.../Logs
Backups dir: /root/security-hardening-backups/
URLs
Admin panel: https://fmhadmin.fmhosting.uk
Client portal: https://fmhbackup.fmhosting.uk
Phil's fixed IP: 149.22.74.121