SSD Nodes Learn Hosting plans →
How to do am Matt ConnorBy Matt Connor

Linux server tools by how many servers you get

Compare SSH config, tmux, Ansible, Uptime Kuma, Zabbix and Webmin by fleet size, setup minutes, wetin each one replace, plus the gotcha wey fit bite you.

Wetín you dey build

No be one tool, na small stack wey you choose based on how many servers you really get. Na that number alone matter, and na the one wey every “Linux server management tools” roundup dey ignore. The usual mistake na to adopt solution for 200 servers when you get four VPSes, then spend one month feeding the tool instead of managing the servers. The second usual mistake na person wey get eighteen servers but still dey SSH into each one by hand, applying “the same” change in eighteen slightly different ways.

So, this guide arrange things by fleet size: 2 to 5 servers, 5 to 20, and past 20, plus the cross-cutting layer wey apply for every size and wey nobody dey write down: inventory, good key hygiene, one way to enter, and backups wey you don actually restore. For each tool, you go get three things: wetin e replace, how many minutes the setup go cost, and the one gotcha wey fit really cause problem. I don run VPS host for fifteen years; na wetin survive contact with 2 a.m. outage dey for the list below, no be wetin demo well.

Prerequisites and real gotchas

You need key-based SSH wey dey work already for every server. If you still dey type passwords, fix that one first; e go take ten minutes, and everything for here assume say keys dey work. You need a sudo user wey no be root, plus servers wey dey run current software. Commands for here assume Ubuntu 24.04, but nothing depend specifically on Ubuntu except apt.

Make we give two honest warnings before the tools. First, too many tools by itself na management problem. Every agent wey you install na another daemon wey you must patch for every box. So, only add one when e go replace manual work wey you do this week, no be because e just look useful. Second, all the things for here na free software. The real cost na setup time. Na why every tool get estimate for minutes. If the estimate talk say na afternoon, believe am.

2 to 5 servers: ~/.ssh/config na the tool wey you already get but people underrate pass

Wetin e replaces: the text file wey hold IP addresses, shell-history archaeology (ssh 203.0 then Ctrl-R and pray), and typing -p 2222 -i ~/.ssh/other_key forever. Setup cost: 15 minutes, na once. The gotcha: stale multiplexing sockets, wey we cover below.

For this size, you no need software; na the client wey you already get you need configure properly. ~/.ssh/config turns every server to one-word name and stores the routing, so you no go need think about am again:

Host *
    ServerAliveInterval 30
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h-%p
    ControlPersist 10m

Host bastion
    HostName 10.0.0.10
    User matt

Host web1
    HostName 10.8.0.11
    User matt
    ProxyJump bastion

Host db1
    HostName 10.8.0.12
    User matt
    Port 2222
    ProxyJump bastion

Three settings dey do the work. ProxyJump routes connections through a bastion with one hop, so ssh db1 from a café go tunnel through bastion transparently, without agent forwarding, ProxyCommand incantations, or public SSH ports for the private servers at all (we go talk more about this for the cross-cutting section). ControlMaster auto with ControlPersist multiplexes connections through one TCP session, so the second and every later ssh, scp, or rsync to the same host go connect instantly instead of renegotiating. The difference dey very obvious when Ansible enter the picture. And because scp, rsync, and Ansible all read this same file, every name wey you define here go work everywhere.

The gotcha be say the master connection fit stay alive after e stop useful, and the two failure modes no look the same. When the server reboot or your Wi-Fi drop, the master process dey hold dead TCP session wey e never notice yet. Then the next ssh web1 go hang quietly on socket wey no lead anywhere. Separately, sshd limits sessions per connection to 10 (MaxSessions for sshd_config), so the eleventh multiplexed session to one host go print:

mux_client_request_session: session request failed: Session open refused by peer

Both problems get the same fix: ssh -O exit web1 kills the master, and the next connection starts a fresh one. Sometimes you fit also see ControlSocket /home/matt/.ssh/cm-matt@10.8.0.11-22 already exists, disabling multiplexing. That one no cause problem: two sessions race, and the connection still works, just without multiplexing.

Two other tools fit help for this size. tmux for each server replaces nohup, prevents work from getting lost when Wi-Fi drop, and solves the “I can't close my laptop, a migration is running” problem. Setup cost na sudo apt install -y tmux, two minutes, plus the muscle memory for tmux new -s work and tmux attach -t work. The gotcha na nesting: tmux inside tmux fit swallow your prefix key, so run am for the server or the laptop, but no run am for both. If you run long-lived agent sessions, this matter twice as much. Na the same pattern as running Claude Code inside tmux for a VPS, where the session must outlive the SSH connection.

A shared alias file replaces retyping your twelve favorite one-liners on every box. Keep a .bash_aliases for a git repo and pull am onto each server. The gotcha be say e go drift immediately when you edit am directly for one server instead of editing am for the repo. This na also your first taste of why the next tier dey exist.

5 to 20 servers: config as code, or drift go win

After five servers, “I go just do am for each box” no longer be method. Na e lie wey you dey tell yourself. All the tools for this level dey fight the same enemy: drift.

Ansible replaces shell loop over hostnames, wiki page wey title be “new server setup” but don dey three steps behind, and worry say you no know whether web3 really get the fix. Setup cost: 30 minutes to first working playbook, sudo apt install -y ansible for your laptop or management box (apt dey give you older Ansible release, and that one okay for everything here; the tutorial pipx route dey give you current versions), no agents for the servers, and everything dey run through the SSH config wey you don already build. Na the biggest single upgrade for this page, and the complete walkthrough dey for the Ansible first-playbook tutorial; this na the inventory structure wey make am work:

[web]
web1 ansible_host=10.8.0.11
web2 ansible_host=10.8.0.12

[db]
db1 ansible_host=10.8.0.21 ansible_port=2222

[all:vars]
ansible_user=matt
ansible_ssh_common_args='-o ProxyJump=bastion'

Because Ansible dey call the OpenSSH binary, the ~/.ssh/config wey you write for the last section don already apply. Inventory of bare names like web1 go work without any vars. The vars above make the inventory self-contained instead. This go help the day you run am from machine wey no be your laptop.

Test am with ansible all -i inventory.ini -m ping; correct result go print "ping": "pong" for every host, with green colour. The first failure wey you fit see go look like this:

web1 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: matt@10.8.0.11: Permission denied (publickey).",
    "unreachable": true
}

This no be Ansible problem. Plain ssh matt@10.8.0.11 go fail the same way. Fix SSH first, always; Ansible fit only be as healthy as the layer under am. The other important issue be say Ansible need Python for your machine and, for almost every module including ping, for the server too. So, truly minimal image fit answer /usr/bin/python3: not found. Run one apt install python3 and e no go disturb you again. For plenty fleet of bare images, the raw module, one of the few wey no need Python for the remote host, fit do that install for you.

unattended-upgrades replaces you as the person wey dey apply security patches to N servers. Stock Ubuntu Server 24.04 dey ship with am preinstalled and normally enabled already for security updates, so the work here na to verify am, no be to install am:

cat /etc/apt/apt.conf.d/20auto-upgrades

Both lines suppose end with "1". Some minimal and cloud images dey ship with am switched off, and sudo dpkg-reconfigure -plow unattended-upgrades go rewrite that file if your own be so. Setup cost: two minutes to check each server, or one Ansible task for all of dem. The issue be say, by default, e no dey reboot. So kernel security updates go remain partly applied until you reboot. The dedicated unattended-upgrades guide explain automatic reboots, how to choose wetin go get patched, and how to read the logs.

Centralized monitoring replaces finding out from customer. Na the most expensive monitoring system wey anybody don design. Two tools, one line each about when to use dem: Uptime Kuma answers “e dey up?”, with HTTP, TCP, and ping checks plus alerts to anything, and e dey take ten minutes for Docker. Zabbix answers “e dey near to fall over?”, with disk, memory, and CPU trends through an agent for every host, and honestly e dey take one afternoon. Start with Kuma. Add Zabbix when “up but degraded” begin cost you money. The issue for both na placement, and e important enough to lead the mistakes section below.

A web panel, only if you must. Webmin replaces remembering where Ubuntu dey keep things. For team with different skill levels, or server wey you touch twice every year, e genuinely useful; setup na ten minutes. The issue be say e be web application with root-level access, and e dey listen on port 10000. Internet scanners dey look for am constantly. If you run am, bind am to localhost or VPN address, never to 0.0.0.0 for public interface. And if you dey reach for panel because SSH dey feel slow, read the previous section again first; ~/.ssh/config plus Ansible dey faster than any panel once you configure dem.

20+ servers: where this guide honestly ends

Past twenty servers, you don dey run a fleet, and the tools go change shape: Terraform or OpenTofu make the servers themselves reproducible, cloud-init or golden images make box disposable instead of repairable, pull-based configuration or CI pipelines wey dey run your Ansible because push-from-a-laptop no dey scale again, plus proper secrets management. Ansible itself no go fail just because you reach twenty; plenty shops dey run am against hundreds of nodes. But the practices around am must become stronger, and that one na different article from wetin this site dey write. If you don reach that scale, the section below still concern you, because inventory, keys, and disciplined access na exactly the things fleet tooling assume say you already get.

Layer wey nobody dey write down

Four practices dey apply no matter how many servers you get. If you skip dem, na why server count dey feel heavier pass wetin e really be.

Inventory file, even if na text file. Once you get three servers, write down: name, IP, provider, wetin dey run for am, and why e dey exist. A servers.md for git repo dey okay; the Ansible inventory wey dey above better because e be executable documentation. Wetin e replace: the 2 a.m. question, “wait, wetin be 10.0.0.40?” Setup cost: ten minutes. The catch: e go only work if creating server and adding the line na the same action, never two separate actions.

Key hygiene: rotate now, use SSH CA when e don become problem. List everywhere your keys dey (cat ~/.ssh/*.pub for your side, ~/.ssh/authorized_keys for each server side), remove ex-laptops and ex-colleagues, and rotate anything old enough wey you no fit talk where e don dey. SSH certificate authority, with short-lived signed certs instead of static keys, na the mature answer. But make we talk true: below ten servers, disciplined authorized_keys management through Ansible go give you 90% of the benefit with 10% of the ceremony.

One way enter, no be twenty. Every public SSH port na attack surface multiplied by N. The pattern wey scale na one bastion host, or better, a WireGuard VPN for VPS wey you control, and make every other server SSH bind only to its private address. The ProxyJump lines for the config above already assume this arrangement. Anything wey must remain public should get fail2ban as normal practice. Setup cost: one hour, once. The catch: confirm say your fallback, the provider console access, dey work before you close port 22 everywhere, no be after.

Test backups by restoring dem. Backup wey nobody don test na only hypothesis. Any mechanism wey you use, provider snapshots, restic, rsync to another box, the tool wey really matter na the calendar entry where you restore one server onto fresh VPS and confirm say e boot and serve traffic. Every backup horror story wey I don hear for fifteen years of hosting get the phrase “we had backups.”

The mistakes

The failure ways for many servers no be tool failures; na habits cause am. Four of dem dey account for almost everything.

Snowflake servers. Person configure each box by hand, each one get small differences, and nobody fit rebuild am. You go discover am when disk fail. The solution no exciting: every change must pass through Ansible, or at least add am to that server section for inventory doc. Any server wey you no fit rebuild from notes this afternoon na technical debt with due date wey you no get to choose.

"Temporary" firewall holes. ufw allow 5432 to debug something, and eighteen months later Postgres still dey internet. Audit with sudo ufw status numbered for each box, or do everything once with ansible all -i inventory.ini -a "ufw status numbered" --become, then delete any rule wey you no fit explain the current reason for. If rule really temporary, put the matching ufw delete for the same tmux window before you close am.

Monitoring hosted on a monitored box. If Uptime Kuma dey run for the server wey e dey monitor, the alert wey say "everything is down" don also go down. You don build smaller, funnier version of the world least efficient datacenter. Monitoring must dey for another failure domain: cheap VPS from another provider na the usual answer. At minimum, use external free-tier check wey dey monitor the monitor.

Root SSH everywhere. One shared root key across the fleet mean say one leaked laptop fit take control of everything, and no audit trail go show who do wetin. Use per-person users, sudo, and PermitRootLogin no inside /etc/ssh/sshd_config for every host. Once again, na three-line Ansible task instead of one evening of typing.

When the fleet grow pass small number of servers, your first Ansible playbook go automate the repetitive parts.

FAQ

Which free tool dey best to manage multiple Linux servers?

For 2 to 5 servers, well-written ~/.ssh/config plus tmux dey beat anything wey you fit install. From around five servers upward, Ansible na the standard answer: e no need agent, e free, e dey run through the SSH wey you already get, and e turn server setup into files for git. Add Uptime Kuma for up/down alerting; every tool wey this guide mention na free software.

I fit manage multiple Linux servers without Ansible?

Yes, for less than about five servers, good SSH config, shared alias file, and discipline dey enough, and plenty people dey work like that for years. Once e pass that number, the alternative to Ansible no be “nothing”; na undocumented drift: eighteen servers wey each person configure by hand in slightly different way. If Ansible seem too heavy, start with one playbook wey only manage authorized_keys and unattended-upgrades; that one alone go pay back the learning effort.

How I go run the same command for multiple Linux servers at once?

ansible all -i inventory.ini -a "uptime" na the clean answer, and e no need playbooks, only the inventory file. For interactive side-by-side work, tmux fit broadcast keystrokes go every pane with setw synchronize-panes on, but treat am like party trick, because broadcasting interactive commands to production servers na how one typo fit cause outage times N.

I need control panel like Webmin to manage Linux servers?

Need, no. Everything wey panel dey do, SSH and Ansible dey do am more reproducibly. Webmin get value when people wey get different skill levels dey administer the same boxes, or when you dey touch server rarely enough that finding config paths again dey waste real time. If you run am, treat am as the root-equivalent web app wey e be: bind am to localhost or VPN address, never to public interface.

How many Linux servers one person fit realistically manage?

With hand administration, quality dey drop somewhere below ten. With config as code, automated patching, and centralized monitoring, one careful person fit run 20 to 50 servers as part-time job. The main constraint go be how often something new break, no be routine maintenance. The number wey matter no be servers per admin but snowflakes per admin: keep that one near zero, and the limit go high.