Why every change to your server is signed twice
5 min read
A server panel holds the keys to every server it manages. Here is how Zefily makes sure a stolen session, or even a compromised panel, cannot quietly change your servers.
Here is an uncomfortable truth about server panels: a panel that can install software, edit configuration and run commands on your servers is, by design, a very attractive target. Break into the panel and you could, in theory, break into every server behind it.
Most panels answer this with good practice: strong sign-in, encrypted secrets, careful code. We do all of that too. But we wanted a stronger promise, one that still holds on a bad day: a stolen session, or even a compromised panel, must not be able to quietly change your servers. This post explains how that works.
In short
- Zefily changes servers only through jobs: structured, schema-checked requests, never a free-form root shell.
- Every job is signed by the panel and by a separate signing service on its own machine, and the agent checks both, plus a sequence number and an expiry.
- Risky actions also need your passkey, verified by the signing service itself.
- Result: a stolen session, or even a compromised panel, cannot quietly change your servers.
Jobs, not shells
Zefily never logs into your server with a root shell and types commands. Every change, from adding a site to renewing a certificate, is a job: a small, structured document that says exactly what to do, with parameters that must match a published schema. Our agent on the server only knows how to carry out these job types. There is no "run whatever the panel says" job hiding in the corner.
That alone removes a lot of risk. But who decides which jobs reach your server?
Two signatures, two machines
Every job is signed twice:
- By the panel, when you click a button, call the API or a schedule fires.
- By a separate signing service that runs on its own machine, at a different provider, with its signing keys in a key management system that never lets them leave. Before it signs, it checks its own policy: is this job type allowed, is this server sending too many jobs too fast, does this job need an approval it has not got?
The agent on your server checks both signatures before it does anything. It also checks a sequence number that only ever goes up and an expiry time, so a job captured on the way cannot be replayed later, reordered or kept for a rainy day.
What does that buy you? Someone who takes over the panel can produce the first signature, but not the second. The signing service does not trust the panel; it applies its own rules and its own rate limits, and it reports anything unusual to us.
Your passkey for the risky things
Some actions are dangerous even when the request is genuine: a root terminal, deleting a site's files or a database, opening a database port to the whole internet, removing the agent, switching the web server, custom nginx directives.
For these, the job waits for your passkey. Your device signs an approval of that exact job, and the signing service checks the passkey signature itself, not the panel's word for it. When an approval is used, you get an email.
So even with a stolen session cookie and a compromised panel, the most destructive jobs still need a passkey that lives in your phone, laptop or security key.
A careful agent
On the server, the agent is split in two. The part that talks to the network runs as an unprivileged user. Only jobs that passed every check reach the small root helper that applies them. Tuning values (memory limits, worker counts and the like) are clamped to safe bounds, so even a valid job cannot ask for something absurd.
And there is no open port for the panel: the agent connects out to Zefily over mutually authenticated TLS. Your firewall stays closed except for SSH and your sites.
A boring example
You click Add site for shop.example.com. The panel builds a site.apply job, checks your permissions and signs it. The signing service checks that site.apply is allowed and not over its rate limit, then signs it too. Your agent receives it, verifies both signatures, the sequence number and the expiry, checks the parameters against the schema, and only then creates the Linux user, the PHP pool, the nginx configuration and the certificate.
You never see any of this. The site simply appears, a few seconds later. Security that works should be boring.
What it does not do
No design makes a system invulnerable, and we would rather be precise than impressive. This model protects your servers from a compromised panel. It does not protect a site from a vulnerable plugin on that site, and it does not replace keeping your own devices and passkeys safe. That is why Zefily also runs a firewall, CrowdSec, automatic security updates, an optional web application firewall and malware scans.
Frequently asked questions
What is dual signing in Zefily?
Every job sent to a server carries two signatures: one from the panel and one from a separate signing service that runs on its own machine with its own policy and rate limits. The agent on the server refuses any job that does not carry both.
What happens if the Zefily panel is hacked?
An attacker could create the panel's signature but not the signing service's, which applies its own rules and reports anomalies. The most dangerous actions also need the customer's passkey, which the signing service verifies itself.
Which actions need a passkey approval?
High-risk ones: a root terminal or command, a reboot, deleting site files or databases, opening a database port to everyone, removing the agent, switching the web server and custom nginx directives.
Does the Zefily agent need an open port on my server?
No. The agent connects out to Zefily over mutually authenticated TLS, so the firewall stays closed except for SSH and your sites.
Can a captured job be replayed later?
No. Each job has a sequence number that only goes up and an expiry time; the agent refuses replayed, reordered or expired jobs.
Read the full security model, or see how approvals work.