Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Static HTML with NGINX and a public asset

Build a small site from HTML and an NGINX configuration, then display a public image from object storage. Complete Before you start first. For an existing frontend project, use Deploying Static Sites. This path uses no language runtime, database, or background worker.

1. Download and inspect the site

Download the static site ZIP, then run:

unzip static-site.zip
cd static-site

The HTML lives in public/index.html:

<!doctype html>
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Hello from d2o</title><h1>Hello from Static Files on d2o!</h1>
<p>Edit this page and push again to deploy an update.</p>
<!-- In the object storage chapter, add an img with your public asset URL. -->
</html>

The buildpack detects the root nginx.conf. Its {{port}} template reads the app’s runtime PORT, while its web root points at the packaged public directory. This example deliberately adds /health; a basic static site can instead use the guide’s default configuration and health path /:

worker_processes 1;
daemon off;
error_log stderr;
events { worker_connections 1024; }
http {
  types {
    text/html html;
    text/css css;
    application/javascript js;
    application/json json;
    image/png png;
    image/jpeg jpg jpeg;
    image/svg+xml svg;
    image/x-icon ico;
  }
  default_type application/octet-stream;
  access_log /dev/stdout;
  client_body_temp_path /tmp/client_body;
  server {
    listen {{port}};
    root /workspace/public;
    location = /health { default_type text/plain; return 200 "ok\n"; }
    location / { try_files $uri $uri/ =404; }
  }
}

To preview just the HTML locally, run python3 -m http.server 3000 --directory public and open http://localhost:3000. This preview does not test NGINX’s template or /health; the deployed image does. Stop it with Ctrl+C before continuing.

2. Create the Environment and app

Dashboard: in Project Examples, create Environment static, type Development, branch main, Automatic deployment on, release source Build. Add a Web Application named site, Framework Static Files, Repository The environment’s shared repository, Directory blank, Process type blank (use the buildpack default), Port 3000, and Health Check Path /health.

CLI:

paas envs create static -o "$TUTORIAL_ORG" -p examples --type development --branch main --release-source build
paas apps create site -o "$TUTORIAL_ORG" -p examples -e static --framework static --shared-source --port 3000 --health-check-path /health

3. Push and verify

git init -b main
git add .
git commit -m "Add static site"

Dashboard path: copy the shared remote command from the Environment’s Git remote panel into this directory, then run its push command. Wait for the app’s successful Deployment and open its public URL.

CLI path:

paas git remote -o "$TUTORIAL_ORG" -p examples -e static
git push d2o main
paas watch -o "$TUTORIAL_ORG" -p examples -e static -a site

Read the public URL in the dashboard, or the url field from paas apps info site --json -o "$TUTORIAL_ORG" -p examples -e static. Open the site, then append /health to its URL; expect ok. A 404 on /health suggests the root NGINX configuration was not packaged or the wrong source directory was selected.

4. Create and upload a public asset

Choose a small image that is safe for anyone to view, saved locally as banner.png. Use a separate bucket containing only public demo assets.

Dashboard: in static, add Object Storage site-assets, tier Capacity, quota 1 GB. Wait for provisioning. In its Files tab upload banner.png. On Overview choose Make public and confirm that every object will be publicly readable. Back in Files, use Copy URL on the image.

CLI: create the private bucket and wait for available: true:

paas buckets create site-assets -o "$TUTORIAL_ORG" -p examples -e static --tier capacity --quota-gb 1
paas buckets info -o "$TUTORIAL_ORG" -p examples -e static -a site-assets

Upload with the CLI, then explicitly make this demo bucket public:

paas buckets put banner.png banner.png --content-type image/png -o "$TUTORIAL_ORG" -p examples -e static -a site-assets
paas buckets visibility public -o "$TUTORIAL_ORG" -p examples -e static -a site-assets
paas buckets url -o "$TUTORIAL_ORG" -p examples -e static -a site-assets

Append /banner.png to the printed public bucket URL. For other S3 tools, see using the AWS CLI.

5. Display the asset

Add this inside public/index.html, replacing the URL with the image’s actual public URL:

<img src="https://your-bucket-host/banner.png" alt="Tutorial banner" width="640">
git add public/index.html
git commit -m "Show public bucket asset"
git push d2o main

Wait for the new Deployment, refresh the site, and confirm the image loads in a private browser window. DevTools should show only the public object URL, with no S3 credentials. There is no need to attach the bucket to the static app. Browser JavaScript must never contain database connection strings or private bucket keys. Use a server-side tutorial when you need authenticated uploads, private downloads, or database queries.

6. Troubleshoot and clean up

If the build cannot detect a web server, check that nginx.conf is at the source root and public/index.html is committed. If the image returns 403, confirm the object key and that this demo bucket is public. If the app fails health checks, confirm Port 3000 and the {{port}} template. View build status in Deployments and runtime errors in Logs, or use paas logs -o "$TUTORIAL_ORG" -p examples -e static -a site.

When done, delete the isolated static Environment in the dashboard’s Environment Settings, or run the command below after confirming it contains only this tutorial. This permanently removes both the site and its bucket data:

paas envs delete static -o "$TUTORIAL_ORG" -p examples --confirm static

Next: Take an Example to Production, including public asset handling and storage recovery.