How To Deploy a Static Website to the Cloud with DigitalOcean App Platform

DigitalOcean can find the GitHub repository and still fail the deployment when the source directory, build command, or output directory points at the wrong place. I kept the sample at a root index.html because that removes two decisions from the first static-site deployment.

I tested the sample through a local HTTP server that requested its heading and stylesheet before the repository moved to App Platform, while generated sites add the build and output steps after the plain HTML path works.

What App Platform deploys for a static site

A DigitalOcean App Platform static-site component builds or reads files from a Git repository, then serves the output through DigitalOcean’s content delivery network instead of running a persistent web server.

Repository typeBuild commandOutput directory
Plain HTML, CSS, and JavaScriptLeave blankThe directory containing index.html
Vite, Astro, Hugo, or another generatorThe project’s production build commandThe generated folder, such as dist or public

DigitalOcean’s current free tier includes three apps with static sites, 1 GiB of data transfer per app, automatic HTTPS, custom domains, and a global content delivery network. Check the App Platform pricing page before launch because a paid service component changes the bill.

What you need before connecting the repository

The deployment source can be GitHub or GitLab, and this walkthrough uses GitHub with a main branch plus a plain static site before showing where a generated site differs.

do-static-site/
├── index.html
├── style.css
└── verify-site.sh

You also need DigitalOcean and GitHub accounts, plus the production build command and generated folder when a framework builds the site.

App Platform scans the repository root by default. A monorepo or nested project needs an explicit source directory, while a generated site needs an output directory that contains the built index.html.

How to deploy a static website to DigitalOcean App Platform

The repository moves from local files to a committed branch, then to a deployed static-site component.

Create a root index.html

A plain HTML site needs no build command, so App Platform can serve the repository contents directly. Save this file as index.html at the repository root.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>DigitalOcean Static Site</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main>
    <h1>The static site is ready</h1>
    <p>This page is served from the repository root.</p>
  </main>
</body>
</html>

The link element makes the stylesheet part of the check. A page that loads while style.css returns a missing-file response is not ready to push.

Verify the local files through HTTP

This check starts a local server, requests the page and stylesheet, then stops the server, so save it as verify-site.sh beside index.html and make it executable.

#!/usr/bin/env bash
set -euo pipefail
python3 -m http.server 3100 >/dev/null 2>&1 &
server_pid=$!
trap 'kill "$server_pid" 2>/dev/null || true' EXIT

for attempt in 1 2 3 4 5; do
  if page=$(curl --fail --silent http://127.0.0.1:3100/); then
    break
  fi
  sleep 1
done

printf '%s' "$page" | grep -q '<h1>The static site is ready</h1>'
asset_status=$(curl --silent --output /dev/null \
  --write-out '%{http_code}' http://127.0.0.1:3100/style.css)
printf 'index.html heading: OK\n'
printf 'style.css status: %s\n' "$asset_status"
printf 'site check: PASS\n'

The shell exits on a failed request or missing heading because set -e is active. Run the check only after style.css exists in the same directory.

chmod +x verify-site.sh
./verify-site.sh
Terminal verification for the static site files
The local check confirms the HTML heading and stylesheet before deployment.

The stylesheet returned HTTP 200, so the local page and its linked asset are available from the same root that a plain static-site component needs.

Commit the verified site to GitHub

Initialize the repository on the main branch and commit only after the local check passes, because I kept the committed main branch clean before adding its remote.

git init -b main
git add index.html style.css verify-site.sh
git commit -m "Prepare static site"
git status --short --branch

Create an empty repository on GitHub, then use the repository-specific commands GitHub shows under push an existing repository from the command line. This keeps the remote URL tied to your account instead of copying a placeholder that cannot authenticate.

Connect the repository in App Platform

Open the DigitalOcean control panel, choose App Platform, and create an app from source code. Select GitHub, authorize access to the repository, choose the repository, and select the main branch.

  1. Confirm the detected component type is Static Site.
  2. Keep the source directory at the repository root for this sample.
  3. Leave the build command blank because the repository already contains deployable files.
  4. Set the output directory to the repository root if the control panel asks for one.
  5. Keep autodeploy enabled when pushes to main should create deployments.

A generated site changes items three and four. Enter the production build command, then point the output directory at the folder that command creates.

ProjectBuild commandCommon output directory
Plain HTMLBlankRepository root
Vitenpm run builddist
Hugohugopublic

Use the folder created by your own build rather than treating the table as a fixed rule. The output directory must contain the index document and every asset referenced by it.

Launch and verify the deployment

Review the plan before launch and remove any service component you did not intend to add. A static site can use the $0 tier, while a web service starts on paid compute.

  • Open the Deployments view and require a successful build.
  • Open View Logs when the build fails.
  • Use Live App and confirm the heading plus the stylesheet.
  • Check a nested route when the site uses client-side routing.

DigitalOcean’s static-assets sample documentation states that a root index.html lets App Platform detect static assets. It also points to the Deployments tab and build logs as the evidence for a successful release.

Fix repository, build, output, and route failures

Deployment failures become quicker to diagnose when you match the visible symptom to the field that controls it. Change one field, create a new deployment, and read the new log before changing another.

SymptomCheckFix
The repository is missingGitHub App permissionsGrant DigitalOcean access to that repository or organization, then reconnect the source.
App Platform cannot find index.htmlSource directoryPoint it at the folder that contains the source index, or set the correct index document.
The output directory does not existBuild command and generated folderRun the production build locally, note the folder it creates, and use that exact folder.
The build command failsDeployment log and runtime settingsUse the command that succeeds from a clean checkout and add required build-time variables.
Nested routes return 404Catch-all documentFor a single-page application, set the catch-all document to index.html.
A push creates no deploymentBranch and autodeployMatch the configured branch to the pushed branch and enable autodeploy.

I checked the generated folder before changing any hosting setting because a missing output directory is a build-result problem. The production build must create the configured folder before App Platform can publish it.

Let the next push prove the setup

Change the heading, commit it, and push to main. A new successful deployment followed by the changed Live App page proves that the repository, branch, build, output, and autodeploy settings agree.

git add index.html
git commit -m "Change the home page"
git push

If no deployment starts, check the configured branch before rebuilding the app. The branch is the trigger, so a clean site on the wrong branch will remain unchanged.

DigitalOcean static-site questions

These answers cover plan and configuration decisions that sit outside the main deployment path.

Is a DigitalOcean App Platform static site free?

DigitalOcean lists a $0 tier with three apps containing static sites and 1 GiB of transfer per app. Paid service components and usage outside the included limits can add charges.

Can App Platform deploy a private GitHub repository?

Yes. The DigitalOcean GitHub App needs permission to read the repository or its organization before the repository appears in the source picker.

Does a plain HTML site need a build command?

No. Leave the build command blank when the repository already contains index.html and the files App Platform should serve.

Can I use a custom domain with the static site?

Yes. Add the domain in the app settings, follow the displayed DNS instructions, and wait for DigitalOcean to provision HTTPS before switching traffic.

Pankaj Kumar
Pankaj Kumar

Pankaj Kumar is the founder and CEO of CodeForGeek, with more than 14 years in IT. He is an open-source enthusiast who enjoys sharing what he learns through CodeForGeek and YouTube, with a focus on Python, data analytics, machine learning, Angular, Node.js, and Kafka.

Articles: 336