Windows 11 · reusable static websites

From an idea to automatic deployment

A repeatable guide to planning with ChatGPT, building locally with Codex, reviewing every Git change, and publishing through GitHub and Cloudflare Pages.

The complete route

One controlled workflow from plan to production

  1. PlanChatGPT
  2. StartGitHub template
  3. BuildCodex locally
  4. ApproveCommit, then push
  5. DeployCloudflare Pages

The reusable starter supplies the structure and safeguards. Each new website becomes its own GitHub repository and local Codex project. Codex edits and tests locally, but a person reviews the diff and separately approves the commit and push. Cloudflare deploys automatically only after the approved commit reaches main.

1 · Prerequisites and software

Prepare the Windows 11 PC

You need a Windows 11 user account with permission to install applications, a GitHub account, a Cloudflare account, and these desktop tools:

  • Git for Windows, which provides Git and Git Credential Manager.
  • GitHub Desktop, used to sign in, clone repositories and see repository state visually.
  • Codex, used to work on a selected local repository.
  • A web browser for GitHub, Cloudflare and the deployed site.

Keep credentials out of the repository. Never paste passwords, access tokens, private keys or account IDs into HTML, project documentation or tracked configuration files.

2 · Git for Windows

Install the version-control foundation

  1. Download and run Git for Windows.
  2. Complete the installer using the normal Windows integration and Git Credential Manager options.
  3. After installation, open a new PowerShell window so Git is available to desktop tools.
  4. Confirm that Git can run before adding repositories.
Git for Windows installer with Git Credential Manager selected as the credential helper
Select Git Credential Manager during installation so GitHub authentication can use the secure browser-based sign-in flow.

3 · GitHub Desktop

Install, sign in and connect GitHub

  1. Install GitHub Desktop and sign in with the GitHub account that owns or can access the repositories.
  2. Complete the browser-based authorisation when GitHub Desktop requests it.
  3. Check that GitHub Desktop shows the correct account before cloning or creating a repository.

GitHub Desktop and Git Credential Manager handle authentication without placing a password or token in the project files.

GitHub Desktop welcome screen offering GitHub.com sign-in
GitHub Desktop begins with a GitHub.com sign-in; complete the authentication in the browser before working with repositories.

4 · Local workspace

Create C:\GitHub

Create C:\GitHub once and use it as the parent directory for website repositories. Each repository gets its own folder, for example C:\GitHub\website-starter and C:\GitHub\website-test.

Keeping repositories together makes them easy to find in GitHub Desktop and Codex. Do not nest one Git repository inside another.

5 · Reusable foundation

Create the website-starter repository

The starter is a dependency-free static website built from plain HTML, CSS and JavaScript. Its public files live under public/, while instructions and planning documents remain outside the deployed directory.

  1. Create or clone website-starter at C:\GitHub\website-starter.
  2. Keep the base homepage, responsive styles, mobile navigation and example page generic enough to reuse.
  3. Add the repository documents described in the next section.
  4. Preview and review the starter before approving its first commit and push.

6 · Repository structure

Know what each file controls

  • public/ contains the only files Cloudflare Pages publishes: HTML, CSS, JavaScript, images and other public assets.
  • AGENTS.md defines mandatory instructions for Codex and other coding agents, including the commit and push approval gates.
  • PROJECT.md records the project purpose, audience, scope and deployment decisions.
  • README.md explains how to start, preview and customise the static website.
  • WORKFLOW.md provides the detailed review, GitHub, Cloudflare Pages, domain and release checklist.

Keeping repository documents outside public/ prevents them from being included in the deployed site.

7 · GitHub template

Make website-starter reusable

  1. Open the website-starter repository on GitHub.
  2. Open the repository settings and enable the Template repository option.
  3. Return to the repository page and confirm the template action is available.

A template creates a fresh repository with the starter files but without treating the new website as a continuation of the starter’s Git history.

GitHub repository settings with Template repository enabled and main as the default branch
The important setting is the checked Template repository option; the default branch remains main.

8 · New repository

Create a website from the template

  1. Use the template action on website-starter.
  2. Choose the GitHub owner, repository name and visibility.
  3. Create the repository, then check that the starter files are present on main.
  4. Keep private repositories private unless the website’s source is intended to be public.
GitHub form creating the private website-test repository from the website-starter template
The new website-test repository is based on website-starter and set to Private before creation.

9 · Local clone

Clone the new repository to C:\GitHub

  1. In GitHub Desktop, choose the new repository from your GitHub account.
  2. Set the local path to C:\GitHub\<repository-name>.
  3. Clone it and confirm GitHub Desktop shows the main branch with no local changes.

10 · Codex project

Add the local repository to Codex

  1. Open Codex and add the cloned repository folder as a project.
  2. Select the exact folder under C:\GitHub, not the parent directory containing every repository.
  3. Start a task inside that project and describe the requested website change.

11 · Agent controls

How Codex discovers and follows AGENTS.md

When Codex works inside the repository, it reads the applicable AGENTS.md. This project’s file requires plain static files by default, focused changes, accessible responsive layouts, full verification, and strict Git approval gates.

The important control is separation of authority:

  • Approval to edit does not approve a commit.
  • Approval to commit does not approve a push.
  • Creating repositories, connecting Cloudflare, deploying or changing DNS needs explicit confirmation.
Codex prompt listing repository rules for AGENTS.md including review and push controls
The initial rules establish repository scope, review before approval, secret protection, and the requirement not to commit or push yet.

12 · Local work

Edit, test and review before Git operations

  1. Ask Codex for a focused change and explicitly state any files or actions that are out of scope.
  2. Codex edits the local files, checks HTML structure, relative links, stylesheet and script paths, and JavaScript syntax.
  3. Codex previews the relevant pages and checks desktop and mobile widths.
  4. Review the changed-file list, complete diff, verification results and any remaining risks.
  5. Request corrections if anything is wrong. No commit is needed while reviewing local changes.
Codex review summary showing the exact homepage changes and desktop and mobile verification
Before approval, Codex reports the exact edited file, requested text, desktop and mobile checks, and confirms that nothing was committed or pushed.

13 · First approval gate

Approve the reviewed commit separately

After the local change is correct, give explicit approval to commit the reviewed files and provide the intended commit message. Before committing, Codex checks that the branch, file list and diff still match what you reviewed.

After the commit, Codex reports the commit ID, branch, Git status, configured remote and outgoing commits. It then stops without pushing.

Codex post-commit report showing commit ID, main branch, clean status and one outgoing commit
The post-commit report confirms that nothing was pushed and clearly identifies the single outgoing commit awaiting separate approval.

14 · Second approval gate

Approve the push only after inspecting the outgoing commit

Review the reported branch, remote and outgoing commit. Then explicitly approve pushing that existing commit to origin/main. Codex verifies the worktree and outgoing count again before pushing.

Afterward, Codex confirms that the worktree is clean, local main matches origin/main, and no outgoing commits remain.

Codex conversation showing separate push approval and successful synchronized Git status
The push is approved in a separate message; the result confirms that local main matches origin/main and no outgoing commits remain.

15 · GitHub authentication

Let Git Credential Manager handle credentials

This setup uses an HTTPS GitHub remote and Git Credential Manager. GitHub Desktop or Git can open a browser-based GitHub sign-in when authentication is needed. Complete that sign-in using the account with repository access.

Do not put a GitHub password or personal access token in the remote URL, tracked files, screenshots or Codex prompts.

16 · Git ownership protection

Resolve a Git safe.directory warning carefully

Git may refuse to use a repository when Windows reports that its directory is owned by a different identity. Check that the folder is the expected local repository before trusting it. For the starter repository in this setup, the recorded fix was:

git config --global --add safe.directory C:/GitHub/website-starter

Use the exact path named in Git’s warning for a different trusted repository. Do not add a broad wildcard or mark unrelated folders as safe.

17 · Cloudflare GitHub access

Grant access to the new private repository

When the new repository is private, the Cloudflare GitHub integration must be allowed to see it before Pages can select it.

  1. Open the GitHub configuration for the Cloudflare integration.
  2. Grant access to the specific new repository when practical.
  3. Return to Cloudflare and refresh the repository selection.
  4. Confirm that the intended repository appears before continuing.

Changing integration permissions affects external access to repository data. Confirm the repository and account before saving the permission change.

GitHub Cloudflare Pages application permissions with Only select repositories enabled
Choose Only select repositories and grant Cloudflare access only to the repositories it must deploy.

18 · Cloudflare Pages

Create the Pages project

  1. Open Workers & Pages in Cloudflare and create a Pages project using Git integration.
  2. Select the GitHub account and the intended repository.
  3. Confirm that the production branch is main.
  4. Enter the no-build settings in the next section, then save and deploy.
  5. Inspect the deployment result and open the generated pages.dev URL.
Cloudflare Pages repository selection with website-test selected
After GitHub permission is granted, website-test appears in Cloudflare and can be selected as the deployment source.

19 · Build configuration

Use the static-site settings

Production branch
main
Framework preset
None
Build command
Leave blank
Build output directory
public

There is no package manager, framework or build step. Cloudflare publishes the contents of public/, leaving AGENTS.md, PROJECT.md, README.md and WORKFLOW.md outside the live website.

Cloudflare Pages build settings showing main, None and blank build fields before public is entered
The screen already shows main, Framework preset None, and a blank Build command. The screenshot was taken before public was entered in Build output directory; enter it before selecting Save and Deploy.

20 · Ongoing delivery

Approved pushes trigger automatic deployments

Once Pages is connected, the normal cycle is local edit → local test → human review → approved commit → separate approved push. When the approved commit reaches GitHub’s main branch, Cloudflare Pages detects it and starts a production deployment.

Check the deployment status, build log and live page after each release. A successful Git push confirms publication to GitHub, but the Cloudflare deployment is a separate process that must also succeed.

Cloudflare Pages Deployments screen showing successful automatic deployment of commit 09fec6e
Cloudflare automatically deployed commit 09fec6e, “Test automatic Cloudflare deployment,” after the approved push to main; the green status check confirms success.
Live Website Test Project homepage confirming automatic deployment from GitHub to Cloudflare Pages
The live Website Test Project displays the updated sentence, confirming that the approved GitHub change reached Cloudflare Pages.

Who does what?

You

  • Choose the scope and content.
  • Review local changes and diffs.
  • Approve commit and push separately.
  • Approve repository and Cloudflare permission changes.
  • Check the final live result.

Codex

  • Read AGENTS.md.
  • Edit and test local files.
  • Report files, diffs and verification.
  • Commit or push only after the matching approval.
  • Verify repository state after Git operations.

Cloudflare

  • Watch the connected GitHub branch.
  • Start a deployment after a push.
  • Publish the public directory.
  • Provide deployment status, logs and the live URL.

21 · Future websites

Repeat the process without rebuilding the foundation

  1. Create a new GitHub repository from website-starter.
  2. Clone it into its own folder under C:\GitHub.
  3. Add that exact repository folder as a Codex project.
  4. Update PROJECT.md, then ask Codex for the website content and design.
  5. Follow the local edit, test, review, commit approval and push approval cycle.
  6. Grant the Cloudflare GitHub integration access to the new repository if needed.
  7. Create the Pages project with main, None, blank and public settings.
  8. Verify the first deployment and every future production update.

23 · Custom domain setup

Connect website-starter.eversden.com to Cloudflare Pages

This setup connects the Cloudflare Pages project website-test to the custom hostname website-starter.eversden.com. The DNS provider is IONOS, so Cloudflare’s My DNS provider method is used.

Add the custom hostname to the Pages project first. Cloudflare must provide and verify the required DNS values. Only then should the matching CNAME record be created at IONOS.

  1. Open the website-test project in Cloudflare Pages and open Custom domains.
  2. Add website-starter.eversden.com as a custom domain.
  3. Choose My DNS provider when Cloudflare asks how DNS is managed.
  4. Keep the Cloudflare instructions open and sign in to IONOS.
  5. Create a CNAME record with name/host website-starter and target website-test-7lw.pages.dev, using the values supplied by Cloudflare.
  6. Save the record at IONOS, return to Cloudflare, and wait for DNS verification. DNS changes can take time to propagate.
  7. Confirm the custom domain status changes to Active.
  8. Confirm the domain’s SSL status shows SSL enabled before treating the hostname as ready.
Cloudflare Pages CNAME setup for website-starter.eversden.com showing the website-starter name and website-test-7lw.pages.dev target
Copy Cloudflare’s exact CNAME values into IONOS: name website-starter and target website-test-7lw.pages.dev.
Cloudflare Pages Custom domains screen showing website-starter.eversden.com as Active with SSL enabled
Setup is complete when website-starter.eversden.com shows Active and SSL enabled.
Pages project
website-test
Custom hostname
website-starter.eversden.com
DNS provider
IONOS
Setup method
My DNS provider
CNAME name/host
website-starter
CNAME target
website-test-7lw.pages.dev
Ready state
Active with SSL enabled

24 · Cloudflare Access and One-time PIN

Protect the custom domain with approved-email sign-in

Cloudflare Access sits in front of the custom hostname and allows only approved email users to continue. The resulting flow is:

website-starter.eversden.com → Cloudflare Access → approved email → one-time PIN → website

  1. In Cloudflare, go to Zero TrustAccessApplications.
  2. Create a Self-hosted application.
  3. Set the destination/public hostname to website-starter.eversden.com and leave Path blank so the application covers the whole hostname.
  4. Create an Access policy named Allow approved email users.
  5. Set Action to Allow and the Include selector to Emails.
  6. Add the approved email used for this test: andy@eversden.com. Do not use the Everyone selector.
  7. Set the authentication provider to One-time PIN.
  8. Turn Accept all available identity providers off.
  9. Turn Apply instant authentication on.
  10. Leave Authenticate with Cloudflare One Client off.
  11. Set the session duration to 24 hours, then save the application and policy.
Cloudflare Access policy named Allow approved email users with Allow action, Emails selector, and andy@eversden.com
The policy uses Allow with the Emails selector and the approved address andy@eversden.com—not Everyone.
Cloudflare Access application settings showing the approved-email policy, authentication toggles, website-starter.eversden.com destination, and 24-hour session duration
Confirm the approved-email policy, identity-provider controls, custom-domain destination, and 24-hour application session before creating the application.
Application type
Self-hosted
Public hostname
website-starter.eversden.com
Path
Blank
Policy
Allow approved email users
Action
Allow
Include selector
Emails
Approved test email
andy@eversden.com
Authentication
One-time PIN
All identity providers
Off
Instant authentication
On
Cloudflare One Client
Off
Session duration
24 hours

Test the protected hostname

  1. Open a different browser or an InPrivate/Incognito window.
  2. Browse to website-starter.eversden.com.
  3. Enter an approved email address.
  4. Receive the one-time PIN by email and enter it on the Cloudflare Access page.
  5. Confirm the website loads after authentication.

A browser with an existing valid Cloudflare Access session may go straight into the website without requesting another PIN. This is expected until the Access session expires; use another browser or an InPrivate/Incognito window to confirm that protection is active.

25 · Troubleshooting checklist

Check each boundary in order

  • Git is not recognised: finish installing Git for Windows and open a new PowerShell or desktop-app session.
  • Git reports dubious ownership: verify the repository folder, then add only that exact trusted path to safe.directory.
  • GitHub asks for credentials: complete the Git Credential Manager browser sign-in with the account that can access the repository.
  • The repository is missing in Cloudflare: update the Cloudflare GitHub integration so it can access that specific repository, then refresh Cloudflare.
  • The wrong files are deployed: confirm the build output directory is public.
  • Cloudflare tries to run a build: confirm Framework preset is None and Build command is blank.
  • A push does not deploy: confirm the commit reached origin/main, the Pages production branch is main, and the project is connected to the correct repository.
  • The deployment fails: inspect the Pages deployment status and build log before changing settings.
  • The live site looks old: compare the deployed commit with the approved GitHub commit, then reload the live page.
  • The custom domain is still pending: allow time for DNS propagation, then confirm the CNAME at IONOS still matches the values Cloudflare supplied.
  • The CNAME is incorrect: use name/host website-starter and target website-test-7lw.pages.dev; do not substitute the full custom hostname in a field where IONOS expects only the host label.
  • SSL is not active yet: wait for Cloudflare to verify the DNS record and provision the certificate. Do not consider setup complete until the domain shows Active and SSL enabled.
  • Access protects the wrong destination: confirm the self-hosted application’s public hostname is exactly website-starter.eversden.com and its Path is blank.
  • One-time PIN is not offered: confirm One-time PIN is the configured authentication provider, Accept all available identity providers is off, and Apply instant authentication is on.
  • An approved email is denied: confirm the Allow policy uses the Emails selector and includes the exact address, such as andy@eversden.com; do not replace it with Everyone.
  • The browser goes straight into the site: an existing valid Cloudflare Access session can bypass another PIN prompt until the 24-hour session expires.
  • You need to confirm protection: test in a different browser or an InPrivate/Incognito window, where no existing Access session should be present.
  • A screenshot does not appear: place it under public/images/setup/ with the recommended filename, then replace the corresponding placeholder block with a relative img element and descriptive alternative text.

For GitHub or Cloudflare screens whose labels have changed, verify the current official documentation before changing repository permissions or production settings.