CoreCP

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.yaml
ACCOUNT  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

  1. If the website has its own placement for that service, that wins.
  2. Otherwise the account's default.
  3. 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-west

This 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 place

The rules the panel will not let you break

It refuses whenBecause
the machine does not carry that rolethe placement would be perfectly consistent and the site would serve nothing
a nameserver set would have fewer than two machinesone published NS looks healthy right up until that machine reboots
a backup would sit on the machine holding the dataa copy on the same disk is not a backup
you remove a role a machine still servesmove the customers off it first
you delete a pool a package still usesprovisioning 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.

WhoJudged on the machine?
administrator, server administratoryes — a machine outside your assignment is outside your authority
reselleronly when creating an account: where does the new one land?
end usernever

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).

PanelFleet → 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 | CoreCP
ssh 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.nl

Three 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 600

You 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 removed

verify_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_HOST has to change in wp-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 samples

Measured 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.