Getting Started with the nginx Chainguard Image

Tutorial on how to get started with the nginx Chainguard Image

The nginx images maintained by Chainguard include development and production distroless images that are suitable for building and running nginx workloads. Images tagged with :latest-dev include additional packages to facilitate project development and testing. Images tagged with :latest strip back these extra packages to provide a secure, production-ready container image.

In this tutorial, we will create a local demo website using nginx to serve static HTML content to a local port on your machine. Then we will use the nginx Chainguard Image to build and execute the demo in a lightweight containerized environment.

If you’d like, you can watch our Getting Started with the nginx Chainguard Image video as you work through this tutorial, which will walk through the same steps that are detailed here.

What is distroless Distroless images are minimalist container images containing only essential software required to build or execute an application. That means no package manager, no shell, and no bloat from software that only makes sense on bare metal servers.
What is Wolfi Wolfi is a community Linux undistro created specifically for containers. This brings distroless to a new level, including additional features targeted at securing the software supply chain of your application environment: comprehensive SBOMs, signatures, daily updates, and timely CVE fixes.
Chainguard Images Chainguard Images are a mix of distroless and development images based on Wolfi. Nightly builds make sure images are up-to-date with the latest package versions and patches from upstream Wolfi.

Prerequisites

You will need to have nginx and Docker Engine installed on your machine to follow along with this demonstration.

For this tutorial, you will be copying code to files you create locally. You can find the demo code throughout this tutorial, or you can find the complete demo at the demo GitHub repository.

Step 1: Setting up a Demo Website

We’ll start by serving static content to a local web server with nginx.

With nginx installed, create a directory for your demo. In this guide we’ll call the directory nginxdemo:

mkdir ~/nginxdemo/ && cd $_

Within this directory, we will create a data directory to contain our content to be hosted by the web server.

mkdir data && cd $_

Using a text editor of your choice, create a new file index.html for the HTML content that will be served. We will use nano as an example.

nano index.html

The following HTML file displays an image of Linky alongside a fun octopus fact.

<!DOCTYPE html>
<html>
<head>
<title>Chainguard nginx Demo Website</title>
<link rel="stylesheet" href="stylesheet.css">
</head>

<body>

<h1>nginx Demo Website</h1>

<h2>from the <a href="https://edu.chainguard.dev/" target="_blank">Chainguard Academy</a></h2>

<img src="linky.png" class="corners" width="250px">

<i><h3>Did you know?</h3></i>
<p>The Wolfi octopus is the world's smallest octopus, weighing in on average at less than a gram!</p>
<p>They are found near the coastlines of the west Pacific Ocean.</p>

</body>

</html>

Copy this code to your index.html file, save, and close it.

Next, create a CSS file named stylesheet.css using the text editor of your choice. We’ll use nano to demonstrate.

nano stylesheet.css

Copy the following code to your stylesheet.css file.

/*
Chainguard Academy nginx Demo Website
*/

body {
    text-align: center;
    background-color: #fcebfc;
    font-family: Arial, sans-serif;
}

h1 {
    color: #df45e6;
}

h2, h3 {
    color: #9745e6;
}

p {
    color: #583ce8
}

.corners {
    border-radius: 10px;
}

After copying the code into the stylesheet.css file, save and close it.

Next, you will pull down the linky.png file using curl. Always inspect the URL before downloading it to ensure it comes from a safe and trustworthy location.

curl -O https://raw.githubusercontent.com/chainguard-dev/edu-images-demos/734e6171ee69f0e0dbac95e6ebc1759ac18bf00a/nginx/data/linky.png

Now, return to the nginxdemo directory you made earlier.

cd ../

Here we will create the nginx.conf configuration file used by nginx to run the local web server. We will demonstrate this using nano.

nano nginx.conf

Copy the following code into the configuration file you created. In the location directive, be sure to update the configuration to reference the path from root to the data directory you created in a previous step. The file path which you are not using should be commented out using the # symbol to prevent syntax errors.

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    server {

        listen 8080;
        server_name localhost;
        charset koi8-r;

        location / {
            root /Users/username/nginxdemo/data; # Update the file path for your system
            #root /home/username/nginxdemo/data; # Linux file path example

        }

    }

    include servers/*;

}

Once you are finished editing the configuration file, save and close it.

Create a new file named mime.types using a text editor of your choice. We will use nano to demonstrate.

nano mime.types

Copy and paste the following code into your mime.types file. This file will allow nginx to handle the HTML, CSS, and png files we created when rendering the webserver.

types {
    text/html                                        html htm shtml;
    text/css                                         css;
    image/png                                        png;
}

Save and close the mime.types file when you are finished editing it.

Next, copy the absolute filepath to the nginx.conf file you created earlier. Replacing the example path with this copied path, execute the following command to initialize the nginx server:

nginx -c /Users/username/nginxdemo/nginx.conf

Please note that you may encounter some permissions errors when executing this command. You will need to update the permissions of the default nginx logging directory on some systems to proceed. For example, nginx installed with Homebrew stores its log files at /opt/homebrew/var/log/nginx/, while on a Linux machine, the logs are stored in /var/log/nginx/. To update the permissions of these directories, execute the following command, updating the log file path if need be.

chmod +wx /opt/homebrew/var/log/nginx/

With the directory permissions updated, you should now be able to initialize the nginx server.

To view the HTML content, navigate to localhost:8080 in your web browser of choice. You will see a simple landing page with a picture of Linky and a fun fact about the Wolfi octopus.

If you make any changes to the files nginx is serving, run nginx -s reload in your terminal to allow the changes to render. When you are finished with your website, run nginx -s quit to allow nginx to safely shut down.

Step 2: Creating the Dockerfile

We will now use a Dockerfile to build an image containing the demo.

In the nginxdemo directory, create the Dockerfile with the text editor of your choice. We will use nano:

nano Dockerfile

The following Dockerfile will:

  1. Start a new build based on the cgr.dev/chainguard/nginx:latest image;
  2. Note which container port we need to expose for nginx to listen on;
  3. Copy the HTML content from the data directory into the image.

Copy this content to your own Dockerfile:

FROM cgr.dev/chainguard/nginx:latest

EXPOSE 8080

COPY data /usr/share/nginx/html/

Save the file when you’re finished.

You can now build the image with:

docker build . -t nginx-demo

Once the build is complete, run the image with:

docker run -d --name nginxcontainer -p 8080:8080 nginx-demo

The -d flag configures our container to run as a background process. The --name flag will name our container nginxcontainer, making it easy to identify from other containers. The -p flag publishes the port that the container listens on to a port on your local machine. This allows us to navigate to localhost:8080 in a web browser of our choice to view the HTML content served by the container. You should see the same HTML page as before, with Linky and an octopus fun fact.

If you wish to publish to a different port on your machine, such as 1313, you can do so by altering the command-line argument as shown:

docker run -d --name nginxcontainer -p 1313:8080 nginx-demo

When you are done with your container, you can stop it with the following command:

docker container stop nginxcontainer

Advanced Usage

In this demo, we did not copy the configuration file into the image built from the Dockerfile. This is because the default configuration file in the image was sufficient for the scope of this demo. If you wish to use a custom configuration file, you must ensure that file paths, ports, and other system-specific settings are configured to match the container environment. You can find more information about making these changes at the Chainguard nginx Image Overview.

If your project requires a more specific set of packages that aren't included within the general-purpose nginx Chainguard Image, you'll first need to check if the package you want is already available on the wolfi-os repository.

Note: If you're building on top of an image other than the wolfi-base image, the image will run as a non-root user. Because of this, if you need to install packages with apk install you need to use the USER root directive.

If the package is available, you can use the wolfi-base image in a Dockerfile and install what you need with apk, then use the resulting image as base for your app. Check the "Using the wolfi-base Image" section of our images quickstart guide for more information.

If the packages you need are not available, you can build your own apks using melange. Please refer to this guide for more information.

Last updated: 2024-08-13 13:25