How to Host a Static Website on Back4app Containers With Docker and nginx [Full Repo]

You have a site and nowhere to put it. Wrap it in a container, point a host at the repository, and it is online — no server to rent, patch or keep running.

The site this guide deploys, live on its own address: a tide-table page headed Porthmeor Beach with cards for next high water, next low water and water temperature, above a seven-day outlook table

You have a website. Some HTML, a stylesheet, maybe a little JavaScript. It works when you open it on your laptop, and now it needs an address other people can type — without renting a server, keeping it patched, or learning what a reverse proxy is.

Putting it in a container solves that. You describe the web server once in a small file, push it to a repository, and a host builds it and runs it for you. There is nothing to maintain afterwards, because there is no machine of yours in the picture.

This guide does it end to end: the site, the container file, the deploy, and a live address. It took 9 seconds from push to live — and the last section explains why most examples you will find online take considerably longer than that.

Watch it instead

The original walkthrough takes a page from a GitHub repository to a running container, start to finish.

Video: Moving a simple Website to Back4App Containers
Watch it instead Moving a simple Website to Back4App Containers
From the Back4app channel. The deployment path is the one below; the container file it writes is the one the last section measures. Open on YouTube →

What do you actually need?

Your files, and one more file beside them. That is the entire list — no server, no hosting account to configure, no web server to install on anything of yours.

The extra file is a Dockerfile. It names a web server, says where your pages go, and that is all it has to do. A host reads it, builds the result once, and runs it.

The example here is a four-file site: an HTML page, a stylesheet, a few lines of JavaScript, and the Dockerfile. Yours can be a thousand pages; nothing below changes.

How do you write the container file?

Three lines. Start from the official nginx image, copy your site into the folder it serves, and declare the port.

FROM nginx:1.27-alpine
COPY site/ /usr/share/nginx/html
EXPOSE 80

That is the whole file. There is no install step, because the image already contains nginx, and no start command, because the image already knows how to start it.

The one value worth knowing is /usr/share/nginx/html — the directory this image serves from. Put your index.html there and the site works; put it anywhere else and you get a 404.

Pin the version in the tag, as 1.27-alpine does here. It means the image you build next month is the image you built today, rather than whatever happens to be current.

How do you get it online?

Push the repository, then point a container app at it. In the dashboard, Web Deployment → choose the GitHub repository → branch and root directory → Create app.

There is nothing to fill in on the way. The platform finds the Dockerfile and marks the build as detected — no build command, no start command, no port, because all three are already answered by the file you wrote.

The Containers deployments panel showing the deployment marked Ready in 9 seconds, the app Available, and a notice that the free plan URL is temporary and live for 60 minutes

The deployment came back Ready in 9 seconds. That is the platform’s own figure, from push to a live HTTPS address, and it is the number the last section of this post explains.

Did it actually work?

Yes — the address serves the real site, not a placeholder. Every file came back at the exact byte size the repository holds, and the server header names the version pinned in the tag.

/            HTTP 200   text/html                2083 B
/style.css   HTTP 200   text/css                 2218 B
/app.js      HTTP 200   application/javascript    204 B

Server: nginx/1.27.5

The JavaScript runs, the stylesheet applies, and the page looks the way it looks on a laptop. A container is not doing anything clever here — that is the point of using one.

Why do most examples build something much bigger?

Because they install the web server instead of starting from one. Nearly every tutorial you will find, including the video above, begins from a general-purpose Linux image and uses the package manager.

FROM ubuntu:latest
RUN apt-get update
RUN apt-get -y install nginx
COPY index.html /var/www/html/index.html
EXPOSE 80
CMD nginx -g "daemon off;"

It works, and the page it serves is identical. What differs is what gets built, pushed and pulled every time you deploy — and the layer breakdown shows where that weight comes from.

Layer, as docker history reports itSize
Ubuntu 26.04 base135 MB
apt-get update43.1 MB
apt-get -y install nginx3.62 MB
COPY index.html20.5 kB

The thing you wanted — a web server and your page — is 3.64 MB, inside an image docker images reports as 254 MB. The apt-get update step, which exists only so the next line can run, is more than ten times larger than the software it fetched.

The package index is a shopping list. There is no reason to ship it with the groceries.

Can you keep the distribution and still be small?

Mostly, yes — and it is worth knowing if you need a distribution for something else. The cost above is not really Ubuntu’s; it is that apt-get update writes its catalogue into a layer, and layers are immutable, so deleting it later reclaims nothing.

Do the install and the cleanup in one instruction and it never gets committed.

FROM ubuntu:26.04
RUN apt-get update \
 && apt-get install -y --no-install-recommends nginx \
 && rm -rf /var/lib/apt/lists/*
COPY site/ /var/www/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

That measures 181 MB — 73 MB smaller, same distribution, same nginx. It also pins the base instead of tracking latest, skips recommended packages, and writes CMD in exec form so nginx receives signals directly.

Image sizeCold buildnginx version
Distribution, as commonly written254 MB12s1.28.3, whatever apt has
Distribution, cleaned up181 MB9s1.28.3, whatever apt has
Official nginx Alpine75.9 MB1s1.27.5, pinned by tag

The three images drawn to scale: 254 MB for the distribution base as commonly written, with 43.1 MB of it marked as the apt package index; 181 MB for the same base cleaned up; 75.9 MB for the official nginx Alpine image

This is where the nine seconds came from. A three-line file has no install step to run, so deploying is a pull and a copy; a file that installs packages repeats that work on every release.

What does the free plan give you?

Enough to put something in front of someone, and not enough to leave running. The container gets 0.25 vCPU, 256 MB of memory and 100 GB of transfer, which is comfortable for a static site.

The limit that matters is the address: on the free plan it is temporary and expires 60 minutes after deployment. That makes it a sharing window rather than hosting — fine for showing a client, not for a site people bookmark. A permanent subdomain or your own domain needs a paid plan.

What should you do next?

Put your own files in site/, change nothing else, and deploy. The container file does not care whether it is carrying one page or a generated documentation site, so the same three lines cover almost every static thing you will build.

Keep the official image for the server you need and pin its tag. Reach for a distribution only when something genuinely requires it — an unusual module, a build step — and when you do, keep the install and its cleanup in a single instruction.

Tagsdockernginxcontainersstatic-sitedockerfileimage-size

Frequently asked questions

How do you host a static website without renting a server?

Put it in a container and let a platform run it. Add a three-line Dockerfile next to your files, push the repository to GitHub, and point a Back4app Containers app at it — the Dockerfile is detected automatically, so there is no build command, start command or port to configure. On September 23, 2026 a four-file site went from push to a live HTTPS address in 9 seconds on the free plan.

What is the smallest Docker image for a static website?

Start from the official nginx Alpine image rather than a general-purpose Linux distribution. On September 23, 2026, serving the same HTML page came to 75.9 MB from nginx:1.27-alpine against 254 MB from an ubuntu:latest image with nginx installed through apt — a 70% reduction for an identical HTTP 200 response.

Why is my Docker image so large after apt-get install?

Usually because apt-get update is its own layer and nothing ever deletes what it downloaded. In a measured build the apt-get update step alone added 43.1 MB of package index to the image, permanently, while the nginx it was needed for added only 3.62 MB. Combining the commands into one RUN and ending it with rm -rf /var/lib/apt/lists/* removes that layer's cost.

Does a smaller container image actually matter?

It matters every time the image moves. The image is rebuilt, pushed and pulled on each deploy, so the difference is paid on every release rather than once. In this comparison a cold local build took 12 seconds for the 254 MB image and 1 second for the 75.9 MB one, and the larger image also carries a package manager, a shell and a full distribution's worth of software that the site never uses.

Should I use ubuntu:latest in a Dockerfile?

Not for anything you intend to deploy twice. The latest tag moves — on September 23, 2026 it resolved to Ubuntu 26.04.1 — so the same Dockerfile produces a different base on a different day, and apt installs whatever nginx that release happens to carry. Pin the base image to a version tag, and let the tag decide when you take the upgrade.

Do I need to change my Dockerfile to deploy on Back4app Containers?

No. Containers builds whatever Dockerfile it finds in your repository, so all three versions in this guide deploy the same way and the choice of base image is entirely yours. That also means the platform rebuilds those layers on every deploy, which is where a 254 MB image quietly costs you time.

Further reading

Reviewed & verified by Back4app Engineering, Editorial review at Back4app

Tested Sep 23, 2026 — Local: Docker 29.4.3, macOS, arm64 · Images: ubuntu:latest (26.04.1), nginx:1.27-alpine · Platform: Back4app Containers, free plan.

More from Back4app Engineering

Containers · tutorial

How to Host a Flutter Web App With Docker, Without Managing a Server [Full Repo]

Containers · tutorial

How to Deploy a Node.js App With Docker and a Database, Without Managing a Server [Full Repo]

Web Deployment · tutorial

How to Deploy a Figma Make Site With an MCP Server [Full Repo]