Where a website is served
A CoreCP website does not live on "a server". It has five services — its web server, its database, its mail store, its nameservers and its backup target — and each of them is placed on a machine independently. Most of the time all five land
Written for: Administrator
A CoreCP website does not live on "a server". It has five services — its web server, its database, its mail store, its nameservers and its backup target — and each of them is placed on a machine independently. Most of the time all five land on the same one, and you never think about it. This page is about the times you do.
Only administrators see any of this. Resellers and end users never see, and never need to see, which machine serves them. That is deliberate: which customer sits on which machine is a map of the platform.
Looking at a placement
Panel — open a hosting account and go to Placement. You see one line per service: the role, the machine, and whether it is active, being provisioned, or moving.
Shell — the same answer:
corecp-panel bindings list --account demo --config /etc/corecp-panel/panel.yamlACCOUNT WEBSITE ROLE NODE STATE SINCE
demo (account default) web stck1.corecp.dev active 2026-08-08 21:07
demo (account default) db stck1.corecp.dev active 2026-08-08 21:07
demo shop.example.com web stck2.corecp.dev active 2026-08-08 21:12(account default) is the answer for every website of that account that has no line of its own. shop.example.com has one, so its web server is on the other machine and everything else about it still follows the account.
How a new account is placed
- If the website has its own placement for that service, that wins.
- Otherwise the account's default.
- Otherwise the policy of the placement pool the customer's package schedules into.
There are three policies. Fewest websites is the default and the one to keep while you are growing: it is the number the panel knows exactly, and it is the one that predicts next year. Lowest load ranks on the machines' last metrics sample, and a machine with no recent sample sorts after every measured one — "we do not know" should not beat "we measured". Random exists for when you want no relationship at all between the order customers arrive in and where they land.
You can always ask before you commit:
corecp-panel bindings plan --account demo --roles web,db --config …ROLE NODE SOURCE WHY
web stck2.corecp.dev policy fewest websites (14) in server group eu-west
db stck2.corecp.dev policy fewest websites (14) in server group eu-westThis changes nothing. The answer also lists every machine that was considered and why each was ruled out, so "why not stck3" is answerable without guessing.
Placement pools
A pool is the set of machines a package may schedule onto — a location, a tier, a generation of hardware. It is not the same thing as a node group: a node group decides who may see a machine, a pool decides what lands on it.
corecp-panel bindings groups create eu-west --org corecp --strategy least_websites
corecp-panel bindings groups list --config …To empty a machine slowly, drain it. Everything on it keeps being served; nothing new is placed there.
corecp-panel bindings groups set eu-west --draining --config …A pool a package still points at cannot be deleted, and the refusal names the packages:
2 package(s) still schedule into this server group (Basic, Pro) — point them
somewhere else first; deleting it would leave provisioning with nowhere to placeThe rules the panel will not let you break
| It refuses when | Because |
|---|---|
| the machine does not carry that role | the placement would be perfectly consistent and the site would serve nothing |
| a nameserver set would have fewer than two machines | one published NS looks healthy right up until that machine reboots |
| a backup would sit on the machine holding the data | a copy on the same disk is not a backup |
| you remove a role a machine still serves | move the customers off it first |
| you delete a pool a package still uses | provisioning would break silently, later |
And two it warns about rather than refusing, because they are trade-offs and not mistakes:
- The web server and the database on different machines, with a slow path between them. Every query on every page pays that number. The panel measures it from the machine itself — not from the panel, which would be measuring something else entirely — and warns above about 2 ms.
- A mail machine with no reverse name for its address. Large providers filter mail from such addresses.
Web and database together is the default, and splitting them is a decision, not an upgrade.
One machine, several resellers
A machine belongs to one node group. A customer belongs to a realm — the root realm, or a reseller's. Those are two different things and they need not agree: that is exactly what shared hosting is. stck1 can sit in the root group and serve the customers of three resellers at the same time.
For a while it could not. The machine counted as a third ownership question on every account-bound call — mail, DNS, FTP, files, backups, WordPress — so the moment a customer sat in a reseller's realm she got 403 node_out_of_scope on her own website. One machine could therefore serve exactly one realm. Since 10 August 2026 placement is what it should be again: an operator question.
| Who | Judged on the machine? |
|---|---|
| administrator, server administrator | yes — a machine outside your assignment is outside your authority |
| reseller | only when creating an account: where does the new one land? |
| end user | never |
Nothing became wider. What you reach is still decided by the account itself: it has to be in your realm and owned by you or by one of your customers. What went away is a question resellers and end users should never have been asked, because they are not shown the answer anyway (see the note at the top of this page).
Panel — Fleet → machines shows a machine's group; Customers shows a customer's realm. They are deliberately not on the same screen, because they are not the same question.
Shell — on the panel machine, straight out of the database, because no screen puts the two side by side:
ssh root@panel1.corecp.dev sudo -u postgres psql -d corecp_panel -c \
"SELECT n.fqdn, o.name AS node_group FROM node n
JOIN organization o ON o.id = n.organization_id ORDER BY n.fqdn" fqdn | node_group
------------------+------------
stck1.corecp.dev | CoreCPssh root@panel1.corecp.dev sudo -u postgres psql -d corecp_panel -c \
"SELECT a.username, o.name AS realm, p.email AS owner
FROM account a JOIN node n ON n.id = a.node_id
LEFT JOIN organization o ON o.id = a.organization_id
LEFT JOIN panel_user p ON p.id = a.owner_user_id
WHERE n.fqdn = 'stck1.corecp.dev'
AND a.username IN ('demo','test200','test300') ORDER BY a.username" username | realm | owner
----------+------------------+------------------
demo | Reseller Test BV | owner@test100.nl
test200 | Reseller Test BV | owner@test200.nl
test300 | CoreCP | owner@test300.nlThree accounts, one machine, two realms. That is what it should look like — and it is exactly what scripts/seed-fixtures.sh puts there; see Using the test set.
Moving one service to another machine
Moving copies customer data and changes what answers for a website, so you have to confirm it explicitly.
corecp-panel bindings move <binding-id> --to stck2.corecp.dev --confirm --wait 600You will see every step:
move 1091ad55-… — web of shop.example.com for demo
stck1.corecp.dev → stck2.corecp.dev, done
STEP STATE DETAIL
preflight done stck2.corecp.dev carries the web role and answers
account_on_target done created demo on stck2.corecp.dev
export_source done demo-web-20260808T210709Z.tar
transfer done 4823040 bytes to stck2.corecp.dev
import_target done imported on stck2.corecp.dev
verify_target done stck2.corecp.dev answered 200 for shop.example.com
cutover done 2 address record(s) now point at stck2.corecp.dev
activate done stck2.corecp.dev now serves the web role
drain_source done stck1.corecp.dev no longer serves shop.example.com; …
cleanup done staged archives removedverify_target fetches the site from the new machine, by its own name, before anything is switched over. If the new machine cannot serve it, the move stops there and the customer never notices.
If it stops halfway
Nothing is lost and nothing is stuck. The old machine kept serving until cutover, and the binding goes back to active where it was. Look at the step that failed, fix what it names, and continue:
corecp-panel bindings moves --state failed --config …
corecp-panel bindings resume <move-id> --wait 600 --config …Resume, not retry. It carries on at the first step that is not finished; the work already done is not done again.
A mail move waits on purpose
A mail move ends in paused, not done. Mail the old machine already accepted is on the old machine, and every mail server in the world still holds the old MX record until its TTL expires. So the old mail store stays readable for four hours, and the binding says draining. Resume the move after that and the old sessions are ended.
paused here means waiting, as designed. It is not a failure.
What a move never does
- It never rewrites a zone somebody else hosts. If we do not host the DNS, the move tells you which record to change and the old machine keeps serving until you change it.
- It never edits your customers' configuration files. If splitting web and database means
DB_HOSThas to change inwp-config.php, the move says so and leaves the file alone. - It never deletes anything a customer owns. The old machine stops serving the site; the files stay, and the step tells you the command that removes them.
Measuring the path between two machines
corecp-panel bindings rtt stck1.corecp.dev stck2.corecp.dev --config …stck1.corecp.dev → stck2.corecp.dev: 0.31 ms over 5 samplesMeasured by the agent on the first machine, connecting to the second — not from the panel, which could be twenty milliseconds from both of them and tell you nothing about the path between them. It uses port 22 unless you name another with --port; the agents' own port is deliberately open to the panel only, so timing that would time a firewall.
Asking the assistant
The assistant can answer "which machine is this customer's site on" and "what moves are running". It cannot start, resume or cancel a move — that is an administrator's action with a confirmation, and not something to do between two sentences of a conversation.