pfcloud / Developers

Guides

Create a site

Create a site of any type, with a Git URL, a GitHub repository, or no code yet, then add DNS and HTTPS.

When to use this

You have an active server and want a new site on it. Scope: sites:write (and sites:read to check). For servers that already run sites, see "Import" at the end.

Site types

type is one of:

Type For Extra fields
laravel Laravel apps php_version, create_database
php Other PHP apps php_version, create_database
static HTML files, or a front end built with a tool: React (Vite, Create React App), Vue, Svelte, Angular. pfcloud runs npm install and npm run build, then serves dist (or build / out if the build writes that) none
nextjs, node Next.js (runs as a server with npm run start) and other Node apps app_port, start_command (see the API reference for the exact rules)
python Python apps app_port, start_command
custom Any language, started by your own command app_port, start_command (required)
docker A Dockerfile at the repository root container_port; the server needs Docker installed
wordpress WordPress installed for you (MySQL or MariaDB servers only) wordpress_title, wordpress_admin, wordpress_email

Common fields: server (public id), domain, aliases, branch, create_database (boolean). The complete list is in Sites.

Three ways to give the site its code

A. A Git URL

curl -s -X POST $MYFORGE/sites \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: create-shop-1" \
  -H "Content-Type: application/json" \
  -d '{"server":"SERVER_ID","domain":"shop.example.com","type":"laravel",
       "repository":"git@github.com:your-org/shop.git","branch":"main",
       "php_version":"8.4","create_database":true}'

For a private repository over SSH, pfcloud's deploy key must be allowed on the repository (the server page and site page show it).

B. A repository from a connected GitHub account

Connect your GitHub account to the team first (team settings, GitHub). Then list accounts and repositories:

curl -s -H "Authorization: Bearer $TOKEN" $MYFORGE/github/accounts
curl -s -H "Authorization: Bearer $TOKEN" $MYFORGE/github/accounts/ACCOUNT/repositories

Accounts show their login. Repositories show full_name and default_branch. Both need sites:read. Then create the site:

curl -s -X POST $MYFORGE/sites \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: create-shop-2" \
  -H "Content-Type: application/json" \
  -d '{"server":"SERVER_ID","domain":"shop.example.com","type":"laravel",
       "github_account":"your-org","github_repository":"your-org/shop"}'

branch is optional here and defaults to the repository's default branch. The site follows the repository through pfcloud's GitHub App, and a push to the branch deploys it. No deploy key or webhook is needed.

C. No code yet

Leave out repository and the GitHub fields. pfcloud creates the site's folder on the server, the Nginx configuration and the database, but the site has no code. It shows as waiting for a repository and cannot be deployed. A deploy request answers 409. Connect a repository later:

curl -s -X PUT $MYFORGE/sites/SITE_ID/github \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: connect-shop-1" \
  -H "Content-Type: application/json" \
  -d '{"account":"your-org","repository":"your-org/shop","branch":"main"}'

For a plain Git address instead of GitHub:

curl -s -X PUT $MYFORGE/sites/SITE_ID/repository \
  -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: repo-shop-1" \
  -H "Content-Type: application/json" \
  -d '{"repository":"git@github.com:your-org/shop.git","branch":"main"}'

This works only while the site has no repository. You can also use the Repository card on the site page. To stop following GitHub use DELETE /sites/SITE_ID/github.

WordPress sites are the exception: they are installed by pfcloud and need no repository.

Wait for it

The answer is 201. Poll GET /sites/{site} until status is active or failed (see Requests and errors). If it failed, read the reason in the dashboard run log, then POST /sites/{site}/retry.

A WordPress answer contains wordpress_admin once (the generated admin password). It is never stored and never replayed, so save it at once.

DNS and HTTPS

  1. Point the domain to the server. If your team connected a DNS provider, POST /sites/{site}/dns adds the missing A records. See DNS and domains.
  2. HTTPS is automatic for sites pfcloud created: once the domain points at the server, pfcloud requests a Let's Encrypt certificate (auto_https is on by default). To ask now, POST /sites/{site}/https. See HTTPS certificates.

Settings after creation

PATCH /sites/{site} accepts auto_deploy, backup_before_deploy, uptime_enabled, uptime_path, health_check_path, build_script, after_deploy_script, start_command, app_port, canonical_host, custom_nginx, php_version. Fields are applied in that order. If one is refused (422), the ones before it are already saved, so send one field per call when that matters.

Import a site that already runs on a server

For servers pfcloud adopted: GET /site-imports?server=SERVER_ID lists importable sites; POST /site-imports imports one (server, domain, type, mode = in-place or watch, run_as, branch); POST /site-imports/all imports all. pfcloud backs up the database first and refuses to import if it cannot.

What can go wrong

Problem Cause and fix
422 plan limit Your plan's site limit is reached. Remove a site or upgrade.
422 domain used The domain is already in the team, or was deleted and is waiting to be purged.
404 on the server The server is outside the token's limits, or not in the team.
Site failed Read the run log, fix the cause (for example a PHP version missing on the server), then POST /sites/{site}/retry.
Deploy 409 No repository connected yet, or the site is not active.