How to Use Chainguard Security Advisories
Article outlining how one can explore and use the Security Advisories found on the Chainguard Container Directory.
Chainguard’s nginx container images provide a security-hardened foundation for web server deployments with significantly fewer vulnerabilities than traditional nginx images. Available in both development (:latest-dev) and production (:latest) variants, these containers maintain full nginx functionality while dramatically reducing attack surface. The production variant uses a distroless approach, removing shells and package managers to enhance security for production workloads.
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 Container 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 Container video as you work through this tutorial, which will walk through the same steps that are detailed here.
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.
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.htmlThe following HTML file displays a graphic 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.cssCopy 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/fb54a9767a5474716398ac33de81d66e263d4c6f/nginx/data/linky.pngNow, 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.confCopy 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.typesCopy 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.confPlease 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.
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 DockerfileThe following Dockerfile will:
cgr.dev/chainguard/nginx:latest container 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 container image with:
docker build . --pull -t nginx-demoOnce the build is complete, run the container image with:
docker run -d --name nginxcontainer -p 8080:8080 nginx-demoThe -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-demoWhen you are done with your container, you can stop it with the following command:
docker container stop nginxcontainerIn this demo, we did not copy the configuration file into the container 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 Container Overview.
If your project requires a more specific set of packages that aren't included within the general-purpose nginx Chainguard Container, 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 a container image other than the wolfi-base container image, the image will run as a non-root user. Because of this, if you need to install packages with
apk addyou need to use theUSER rootdirective.
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 Container" 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: 2025-07-23 15:09