Handpress on cPanel

Ordinary shared hosting is the best place to run this: the files are right there, so a save is live the moment the client presses it.

On Cloudflare a save waits for a deploy. Here there is nothing to wait for — the editor writes the HTML file, and the next visitor gets it. Git is still used for history, when the host allows it.

What you need

RequiredcPanel with PHP 8.1 or newer and the curl extension (both are standard), and a domain or subdomain with HTTPS — cPanel's AutoSSL does this free.
Nice to haveTerminal or SSH access, and Git Version Control in cPanel. With them, every save is also a git commit pushed to your repository. Without them, Handpress keeps timestamped backups instead — see Without SSH.
On your own machineNode, to run the two handpress commands. Nothing is built or compiled; you are only copying files and adding keys.

A word on layout. On cPanel your site lives in public_html (or public_html/subdomain), and your home directory is one level above it. That distinction matters: the settings file holds your keys and must sit in the home directory, where the web server will not serve it.

/home/youruser/
├── handpress-config.php     ← settings and keys, never reachable from the web
├── handpress-sessions/      ← created automatically
├── handpress-backups/       ← created automatically
└── public_html/             ← the site itself
    ├── index.html
    ├── about.html
    ├── editor.js
    ├── admin.html
    ├── api.php
    └── uploads/

1. Put the site on the server

With Git Version Control (preferred)

In cPanel, open Git Version Control → Create, tick Clone a Repository, give it your repository URL and set the path to public_html. For a private repository, first add the server's key to it: cPanel → SSH Access → Manage SSH Keys, generate a key, then add the public key to your repository as a deploy key with write access.

Write access matters: it is what lets each save push back.

Without git

Zip your site, upload it in File Manager, and extract it into public_html. Saves will still work; they just won't be committed.

2. Add the editor

On your own machine, in your site's repository:

npm i -D handpress
npx handpress install ./public_html --php
npx handpress keys "public_html/*.html" --global "header, footer"

The --php flag adds the server half: api.php, the two Apache templates, and a sample settings file placed one level above the site.

Then add this to your site's own JavaScript, so visitors never load the editor:

if (/(?:^|;\s*)ed=1/.test(document.cookie)) {
  var s = document.createElement('script');
  s.src = '/editor.js'; s.defer = true;
  document.head.appendChild(s);
}

handpress keys reformats your HTML as well as adding keys. Commit that on its own, before any content change — otherwise your first real edit is buried in a whole-file diff.

Commit and push, then pull on the server (Git Version Control → Manage → Pull or Deploy), or upload the changed files by File Manager.

3. Settings above the web root

In File Manager, go up from public_html to your home directory, rename handpress-config.sample.php to handpress-config.php, and edit it:

return [
    'admin_emails' => ['owner@example.com'],
    'google_client_id' => '…apps.googleusercontent.com',

    'pages' => ['index.html', 'about.html'],
    'data_files' => ['data.js' => 'Opening times'],
    'global_blocks' => ['header', 'footer'],
    'upload_dir' => 'uploads',

    'git' => true,        // false if the host has no shell access
    'backups' => true,
];

Set its permissions to 600 (File Manager → right-click → Change Permissions, or chmod 600). Only your account needs to read it.

pages is the allowlist. A page that is not listed cannot be read or written by anyone, including a signed-in admin.

4. Apache rules

In File Manager, turn on Settings → Show hidden files (dotfiles), then:

  1. The site's rules

    Rename htaccess.txt in public_html to .htaccess. If you already have one — a WordPress install, a redirect — paste the Handpress block at the top of the existing file instead of replacing it.

    It routes /api/… to api.php, gives you clean URLs, and returns 404 for the parts of your repository that are not the website (.git, node_modules, Markdown files, the settings file).

  2. The uploads rules

    Create the uploads directory inside public_html if it does not exist, and move uploads-htaccess.txt into it as .htaccess.

    This is the one that matters most on shared hosting: it means whatever lands in that directory is served but never executed.

5. PHP version

cPanel → Select PHP Version (sometimes MultiPHP Manager) → choose 8.1 or newer for this domain. In the extensions list, make sure curl is ticked: sign-in uses it to check the token with Google.

If Select PHP Version offers disable_functions, leave shell_exec enabled if you want git commits. Handpress works without it and simply skips the commit.

6. Google sign-in

  1. Create the OAuth client

    In the Google Cloud console: APIs & Services → Credentials → Create credentials → OAuth client ID → Web application.

  2. List your site as an origin

    Under Authorized JavaScript origins, add https://yourdomain.com (and the staging subdomain, if you have one). No redirect URIs are needed.

  3. Put the client ID in the settings file

    Copy it into google_client_id, and put the owner's Google address in admin_emails. That address is the whole of the access control: anyone on the list may edit, everyone else is refused.

Make sure HTTPS is on first — cPanel → SSL/TLS Status → Run AutoSSL. The session cookie is marked Secure, so sign-in will not stick over plain HTTP.

7. Check it

Visit https://yourdomain.com/admin and sign in. The site should reappear with an editor bar along the bottom. Then run through this list — it takes two minutes and catches the things that matter:

Edit text on two pages and saveThe change is live immediately. If git is on, a commit appears in your repository.
Edit the footer and open another pageThe change is on every page.
Duplicate a card or list item, then delete itBoth survive a save.
Replace an imageThe new file appears in uploads/ and is served.
Open yourdomain.com/uploads/Should not list the directory.
Open yourdomain.com/.git/config and /handpress-config.phpBoth must return 404. If either downloads, stop and fix the .htaccess.
Open the site in a private windoweditor.js must not load, and /api/me must return 401.

Without SSH

Plenty of cheap cPanel plans have no Terminal and no git. Handpress still runs; you lose the commit history, not the editing.

Set 'git' => false in the settings file. Every save then keeps a timestamped copy of each file it is about to overwrite, in handpress-backups/ above the web root, and the last hundred saves are kept.

To restore something, open File Manager, find the dated folder, and copy the file back into public_html. It is cruder than git revert, but it has saved the same afternoon of work.

If your plan has git but no shell, cPanel's Git Version Control can still pull deployments from your repository — but it cannot push the client's edits back. Treat the server as the source of truth in that case, and pull from it when you next work locally, or you will overwrite their changes.

Troubleshooting

What you seeWhat it usually is
Sign-in page loads, but the Google button never appearsgoogle_client_id is empty, or your origin is not listed in the OAuth client. Both are exact-match: https://www.example.com and https://example.com are different origins.
"Google sign-in could not be verified"The client ID in the settings file does not match the one the page used, or curl is disabled for this PHP version.
You sign in, then immediately get "Please sign in again"The session is not persisting: the site is not on HTTPS, or the home directory is not writable for handpress-sessions.
404 on /api/config.htaccess is missing (hidden files are off in File Manager), or mod_rewrite is off. Test with /api.php?route=config — if that works, it is the rewrite.
"This page can't be edited"The page is not in pages, or it has no keys because handpress keys was not run, or the file you uploaded is not the keyed one.
"Could not write … Check the folder's permissions"Files should be 644 and directories 755, owned by your cPanel user. If you uploaded as a different user, fix ownership in File Manager.
Save works, but nothing is committedExpected without shell access. With it: check .git exists in public_html, and that the deploy key has write access.
The editor sits on "Publishing…"Something is serving a cached copy — often a CDN or a cPanel cache in front of the site. The editor waits for the page it just wrote.
Clean URLs broke an existing appDelete the clean-URL block from .htaccess; only the /api/ rule is required.