How to Deploy a Static Website from GitHub (HTML, CSS and JavaScript)
A website made of HTML, CSS and JavaScript files needs no server code, no database and no build step. Put it in a GitHub repository and Chajio Cloud serves it over HTTPS, on a free address or your own domain, and publishes it again every time you push. This guide shows how to lay out your files so the right ones are public, how to link between pages, and how to get it live.
On this page
Before you start
- A Chajio Cloud App Hosting plan. The Free plan is enough to follow along. Once you order, you get an email with your sign-in details, and the first time you sign in you choose your own password.
- Your code on GitHub, in a repository you own or can access. A public repository you don't own works too.
- Your site’s files: HTML pages, with the home page named
index.html, plus any CSS, JavaScript and images. A template you downloaded works as well as a site you wrote.
Step 1: Organise your files
A repository with an index.html, either at its root or in a folder called public, is served as a static site. Nothing is installed or built: the files go out as they are, compressed automatically.
Put the site in public/
Which folder holds index.html decides what anyone can download. With it in public/, only that folder is served, so a README.md, notes or drafts at the root of the repository stay private. With it at the root, every file in the repository is public, including a notes.txt or a .env you committed by mistake. Unless the repository holds nothing but the site, use public/:
README.md not served
public/
index.html https://your-site/
about/index.html https://your-site/about/
contact.html https://your-site/contact.html
css/style.css
js/main.js
img/logo.pngLink to pages the way they are named
An address must match a file. /contact.html works, and /contact without the .html returns 404. Folders are the exception: /about/ serves about/index.html, and /about redirects to /about/. So for tidy addresses, give each page its own folder with an index.html inside:
<nav>
<a href="/">Home</a>
<a href="/about/">About us</a>
<a href="/contact.html">Contact</a>
</nav>
<link rel="stylesheet" href="/css/style.css">Links that start with / work from any page. If you open your files straight from your computer to preview them, use a small local server such as VS Code’s Live Server, since / means the root of your disk there.
What makes it something other than a static site
The platform looks at your repository’s top folder to decide what it is, and a static site is the last thing it checks for. These files make it another kind of app instead:
- A
package.jsonmakes it a JavaScript project. With Vite in it, the app is built and served as in the Vue.js guide; without, it is run as a Node.js server, which a plain HTML site isn’t. If you use one only for tools on your computer, such as a CSS builder, commit the built files topublic/and leavepackage.jsonout of the repository. - A
Procfile, anindex.php, or the files of another language, such asrequirements.txtorcomposer.json, make it that language’s app.
Your 404.html isn’t used
A missing page returns a plain “404 Not Found” page, with the 404 status code search engines expect. A 404.html of your own is served only if someone opens it by name, so you don’t need one.
Step 2: Create a project
A project is the home for one app, along with its database and domain. In your dashboard, open Projects and click New project:
- Name
- Lowercase letters, numbers and hyphens, up to 24 characters. It becomes part of your app’s free web address and can’t be changed later, so pick something short, like shop or api.
- Plan
- The plan the project draws its resources from.
- Resources
- CPU, memory and storage for this project, pre-filled with what your plan has left. The defaults suit most apps.
Click Create project. Setting it up takes about a minute, and you land on the deploy guide straight away, which walks you through three short steps: Source, Configure and Deploy. You can pick your repository while the project finishes setting up.
Step 3: Connect your repository
On the Source step, choose where your code comes from:
- Your repository
- Click Connect GitHub and approve access, which lets Chajio Cloud read your code and hear about your pushes. Then choose the repository and the branch to deploy, usually main. From now on, every push to that branch deploys automatically.
- Public repository
- Paste the URL of any public GitHub repository, no GitHub sign-in needed. Since you don’t own it, pushes can’t trigger deploys: deploy by hand, or tick Auto-deploy new releases to follow the project’s published releases.
If your app lives in a subfolder of the repository, as in a monorepo, set Build context to that folder, for example apps/web. Otherwise leave it as ., the repository root. Then click Connect repository and Continue.
Step 4: Configure
The Configure step has two runtime settings, both changeable later without a rebuild, and your environment variables.
- Container port
- Leave it at 3000. The server that serves your files listens on whatever port is set here.
- Health check path
/, the default. Your home page answers it.
A static site has no build and no server code to read environment variables, so you can skip them.
Click Save and continue.
Step 5: Deploy
The Deploy step shows a summary of the repository, branch and build context. Click Deploy now and the build log starts streaming: your code is fetched, dependencies are installed and your app is built and started. The deployment moves through Queued, Building and Deploying to Success.
The first build takes a few minutes. Later builds reuse the parts that didn't change, so they are usually quicker. When it finishes, your app is live on a free live.chajio.cloud address with HTTPS already switched on. You'll find the address on the project's Overview.
If the deployment fails, the dashboard names the stage that broke and why, and the build log shows the details. Our troubleshooting guide covers the usual causes.
A static site’s build log is short, because there is nothing to install:
▸ No Dockerfile - detecting your stack
▸ Serving it as a static site (HTML)
▸ Build-time variables: none
▸ Detecting the stack…
▸ Stack: Static web server · HTML
▸ Building…
▸ Exporting the image…In our tests the whole deploy took under two minutes, and the site was ready the moment it started, using about 10 MB of memory.
Connect your domain
Your app already works on its free address. To serve it from your own domain, open the project's Domains tab:
- Enter your domain, for example
www.example.com, and click Add domain. - The dashboard shows two DNS records to add where your domain's DNS is managed. A TXT record proves the domain is yours. A CNAME record routes visitors to your app, or an A or ALIAS record for a root domain like
example.com. Copy the values exactly as shown. - Click Verify. Once both records check out, a free HTTPS certificate is issued automatically, usually in under a minute, and your app is live on your domain.
DNS changes can take a while to spread, so if Verify doesn't find a record yet, give it a few minutes; the dashboard also re-checks on its own. The full walkthrough, including root domains and Cloudflare, is in How to connect your domain to your app.
After launch
- Every push deploys. Push to your branch and a new deployment starts on its own. Your current version keeps serving visitors until the new one passes its health check, so updates don't cause downtime. You can also deploy by hand from the Deployments tab.
- Roll back in seconds. If a release misbehaves, open Deployments and click Rollback to this version on an earlier successful deployment. Nothing is rebuilt; the previous version simply comes back.
- Watch it run. The Logs tab streams your app's output live, with secrets hidden. The Overview shows your app's status and address, with Redeploy, Restart and Stop buttons.
Your app runs as two copies
Every plan runs two copies of your app, so a crash or an update never takes it offline. That has one consequence worth designing for: anything an app keeps only in its own memory or on its own disk isn't shared with the other copy, and it's gone after a redeploy.
A static site has nothing to keep between visits, so both copies serve exactly the same files and there is nothing to plan for. If you add a contact form, send it to a form service or to an API you deploy as an app of its own: a static site has no server to receive it.
Static site hosting or web hosting?
Both can put an HTML site online. Which suits you depends on how you work:
- Static site hosting suits a site you keep in GitHub and want published on every push, with each version a click away if you need to roll back. It is part of App Hosting, so the same plan can run your API or app next to it.
- Web hosting suits most business websites: email accounts on your domain, a control panel, file uploads without Git, PHP and one-click WordPress. See our web hosting plans, or Choosing the Right Hosting Plan for Your Business if you aren’t sure.
Common problems
A page works as /about.html but not as /about
Addresses must match files. Link to about.html, or move the page to about/index.html and link to /about/.
A file you didn’t mean to publish can be downloaded
With index.html at the root, everything in the repository is public. Move the site into public/, or remove the file from Git and push again.
The deploy fails asking for a start command
There is a package.json in the repository without Vite, so your site is being built as a Node.js app. Remove it from the repository, or add a build with Vite.
Styles or images are missing on some pages
A relative link such as css/style.css breaks on pages inside folders. Start the link with a /, as in /css/style.css, so it works from every page.
For anything else, Deployment Failed? How to Find and Fix the Cause explains how to read a failed deployment. Plans and a summary of everything here are on the static site hosting page.
Learning path
Deploy your first app
- 1
- 2
- 3
- 4
Keep reading
How to Connect Your Domain to Your App (with Free HTTPS)
Put your app on your own domain in three DNS steps. Covers www versus root domains, what each DNS record does, Cloudflare, and what to check when a domain will not verify.
How to Deploy a Vue.js App (Vite, Vue Router and Pinia)
Deploy a Vue 3 app made with create-vue straight from GitHub, with no changes. How Vue Router history mode works, VITE_ variables, choosing a Node.js version and connecting your own domain.
How to Deploy a React App
Take a React app built with Vite or Create React App from your GitHub repository to a live HTTPS address, with environment variables, your own domain and automatic deploys on every push.
Choosing the Right Hosting Plan for Your Business
Shared, VPS, eCommerce, or Enterprise? This guide breaks down each hosting type so you can make a confident, well-informed decision for your website or application.
Host your static site on Chajio Cloud
Free for your first month, with a managed database and two replicas of your app on every plan.