Containers: Deploying a static website with nginx and Podman
This document will guide you through the process of creating and running a static HTML website in a container on a personal computer, using Podman for the containerisation and nginx as the web server. The focus is container management, it will not cover how to publish the website to the internet.
Contents
Terminology and concept
The traditional way of setting up a web server was to download the webserver executable, then install it, then configure it, and tell it where on the computer your HTML files are located. With containerisation, you download a web server image from a registry, then create your own version of that image with your HTML files and configuration within it, then deploy it to be run in a container by a virtualisation engine such as Docker or Podman.
Explore the Podman environment
Before we start, let's familiarise ourselves with some Podman commands in a Terminal window. We can use the podman system info
command [docs] to see how Podman is configured. The entry for registries will be important later.
$ podman system info
[ ...snip ]
registries:
search:
- registry.fedoraproject.org
- registry.access.redhat.com
- docker.io
- quay.io
[ snip... ]
We can list all our running containers with podman container list
[docs], but need to add the --all
option to include ones which are not running. We have no containers yet.
$ podman container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Images we download or build for ourselves are listed with podman image list
[docs]. This list is also empty.
$ podman image list
REPOSITORY TAG IMAGE ID CREATED SIZE
Download an nginx image
An image is downloaded with the podman image pull
command [docs]. Here, the image name and a version tag are specified—we want the latest version of nginx. Because no registry was named, Podman offers all the registries it has been configured to use. The selected one will be reused automatically the next time an nginx image is pulled.
$ podman image pull nginx:latest
? Please select an image:
registry.fedoraproject.org/nginx:latest
registry.access.redhat.com/nginx:latest
▸ docker.io/library/nginx:latest
quay.io/nginx:latest
✔ docker.io/library/nginx:latest
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob 398157bc5c51 done |
Copying blob c57ee5000d61 done |
Copying blob f24a6f652778 done |
Copying blob 9b0163235c08 done |
Copying blob 9f3589a5fc50 done |
Copying blob f0bd99a47d4a done |
Copying blob 1ef1c1a36ec2 done |
Copying config b690f5f0a2 done |
Writing manifest to image destination
b690f5f0a2d535cee5e08631aa508fef339c43bb91d5b1f7d77a1a05cea021a8
Podman has created a long ID for the image, but the first 4 characters are sufficient to refer to this image in commands for managing it. The list of images will now have something in it!
$ podman image list
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/nginx latest b690f5f0a2d5 3 months ago 191 MB
Create a container
To create a container from the pulled image, use podman container create
[docs]. Give the container a name, and tell Podman that it should use the nginx image. The --publish 8080:80
option tells Podman to make the container's port 80 available via port 8080 on the host computer.
$podman container create --name webserver --publish 8080:80 nginx
8d491547a2f21e777551da3dcafae2a8218b614a6e54b8a33a994d888f8175bf
That's another long ID, and there will be something in the list of containers now.
$ podman container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8d491547a2f2 docker.io/library/nginx:latest nginx -g daemon o... 33 seconds ago Created 0.0.0.0:8080->80/tcp webserver
Start the container
The container can be started with the podman container start
command [docs], with the name of the container being specified.
$ podman container start webserver
webserver
The list of containers now confirms that the container has been started. Opening http://localhost:8080/ in a web browser will show the nginx Welcome page.
$ podman container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8d491547a2f2 docker.io/library/nginx:latest nginx -g daemon o... 2 minutes ago Up About a minute 0.0.0.0:8080->80/tcp webserver
Build a custom image
Deploying the nginx Welcome page is reassuring but not very practical, so that container is of no use. It needs to be stopped and removed, and then we can deploy an actual website. We need the commands podman container stop
[docs] and podman container rm
[docs].
$podman container stop webserver
webserver $podman container rm webserver
webserver $podman container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
To build a custom image with our own website in it, we need a directory to work in, and a Dockerfile to let the build process know what to do. The Dockerfile is just a file named Dockerfile, and the working directory can be created anywhere. The Dockerfile below will build a new image based on the nginx image, and copy our content
subdirectory into a directory within the new image.
Dockerfile commands:
FROM nginx COPY content /usr/share/nginx/html
Our working directory contents:
$ tree
.
├── content
│ └── index.html
└── Dockerfile
2 directories, 2 files
The podman build
command [docs] uses --tag
as the option for naming the resulting image. The .
denotes the directory the build will run in—our working directory. When the build is complete, the new image appears in the image list; its repository is localhost.
$podman build --tag my_nginx .
STEP 1/2: FROM nginx STEP 2/2: COPY content /usr/share/nginx/html COMMIT my_nginx --> 4e619540f3c4 Successfully tagged localhost/my_nginx:latest 4e619540f3c4f444cc945d16baf542674898c79676253625a70e577810226b0c $podman image list
REPOSITORY TAG IMAGE ID CREATED SIZE localhost/my_nginx latest 4e619540f3c4 22 seconds ago 192 MB docker.io/library/nginx latest b690f5f0a2d5 3 months ago 191 MB
Deploying the image in a container is the same process as before, but the new image must be specified instead of nginx.
$podman container create --name webserver --publish 8080:80 my_nginx
9403862d3199a7a0083ee53b59454659da7ff7f2f583c16774eb629fca3ae1a8 $podman container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9403862d3199 localhost/my_nginx:latest nginx -g daemon o... 15 seconds ago Created 0.0.0.0:8080->80/tcp webserver $podman container start webserver
webserver $podman container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9403862d3199 localhost/my_nginx:latest nginx -g daemon o... 37 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp webserver
Opening http://localhost:8080/ in a web browser now shows your own website. The nginx Welcome page might have been cached by your browser, in which case you'll need to do a hard refresh: Ctrl+Shift+R.
Other Approaches
The method above is satifyingly simple, once you have learned the basics: the base image contains everything in your project or application which is constant, and the build process handles anything which can change from version to version.
If you need to alter the default setup of nginx, you might choose to add a line to your Dockerfile to copy configuration files in each build. But if the setup does not often change, you could create a new base image with the configuration files already in it, and build your website from that. To remove the default nginx configuration files, you would use RUN
in your Dockerfile to run the rm
command within the image, before using COPY
as above.
FROM nginx RUN rm /etc/nginx/nginx.conf /etc/nginx/conf.d/default.conf COPY website-config /etc/nginx
If you want something more bespoke, you could start with a fresh container and install everything you need. This is less divergent from the traditional model, but retains the benefits of containerisation, such as having no side-effects on other services and being easily repeatable. Fedora has an example which takes a base image of their own Linux distribution and uses their package manager, dnf, to install the httpd web server.
FROM fedora:latest RUN dnf -y update && dnf -y install httpd git && dnf clean all COPY index.html /var/www/html/index.html EXPOSE 80 ENTRYPOINT /usr/sbin/httpd -DFOREGROUND
Fedora's example uses the Dockerfile to expose port 80, which we did when we created our container with podman container create
↑ . Other instructions can be added to the command line rather than a Dockerfile, as this example from nginx themselves shows. It uses the docker run
command [Podman docs] to create and start a container, and has the --mount
option to copy /var/www
to /usr/share/nginx/html
.
$ docker run --name mynginx2 --mount type=bind,source=/var/www,target=/usr/share/nginx/html,readonly --mount type=bind,source=/var/nginx/conf,target=/etc/nginx/conf,readonly -p 80:80 -d nginx