yum upgrades for production use, this is the repository for you.
Active subscription is required.
The NGINX untar module lets NGINX serve individual files from inside a tar archive — without extracting them first. It reads tar archives on the fly and delivers individual files directly to clients using zero-copy I/O. If you manage servers that host large collections of static files, the NGINX untar module eliminates the need to extract archives to disk entirely.
This capability solves a practical problem for system administrators. Instead of extracting thousands of files across the filesystem, you keep everything in a single tar archive. NGINX opens the archive, locates the requested file by its offset, and streams it to the client using sendfile(). The archive never needs to be decompressed or unpacked. This approach works especially well alongside other NGINX performance features like proxy buffering and dynamic ZIP assembly.
How the NGINX Untar Module Works
The NGINX untar module parses uncompressed tar archives and builds an in-memory index of every file entry. When a request arrives, the module looks up the requested filename in this index, finds the byte offset within the archive, and serves that exact range of bytes as the response.
Internal Architecture
Here is what happens when NGINX processes a request through the untar module:
- Archive discovery — The module evaluates the
untar_archivedirective to determine which tar file to open. This value can include NGINX variables, so different requests can target different archives. -
Index caching — On first access, the module reads all 512-byte tar headers sequentially and builds a red-black tree index of filenames, sizes, and offsets. This index is cached in shared memory across all requests.
-
Cache validation — On subsequent requests, the module compares the archive’s file size and modification time against the cached values. If either has changed, the index is rebuilt automatically. This means you can update archives without restarting NGINX.
-
File lookup — The requested filename is looked up in the red-black tree. Lookup time is O(log n), making it efficient even for archives containing thousands of files.
-
Zero-copy delivery — The module creates an NGINX buffer pointing directly to the file’s position inside the archive. NGINX then uses
sendfile()to transmit the data from the archive file descriptor to the client socket, bypassing userspace entirely.
What Gets Served
The module automatically detects content types based on file extensions using NGINX’s built-in MIME type mapping. A file named style.css inside the archive gets served with Content-Type: text/css. A file named app.js gets application/javascript. This works exactly like serving static files from the filesystem.
Response headers include Content-Length, Last-Modified, ETag, and Accept-Ranges. Clients can make range requests against files inside the archive, which is important for resumable downloads and media streaming.
Tar Format Support
The module supports the standard POSIX tar format (ustar) and GNU tar long filename extensions. It handles:
- Regular files (typeflag
0or null byte) - Long filenames via GNU extension (typeflag
L) - Files larger than 8 GB using GNU binary size encoding
The module does not support compressed archives (.tar.gz, .tar.bz2, .tar.xz). Only plain .tar files work. Attempting to use a compressed archive will produce a 500 Internal Server Error with “Unable to read tar header” in the error log.
Installation
RHEL, CentOS, AlmaLinux, Rocky Linux
Install the module from the GetPageSpeed repository:
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-untar
Then load the module by adding this line at the very top of /etc/nginx/nginx.conf (before the events block):
load_module modules/ngx_http_untar_module.so;
Debian and Ubuntu
First, set up the GetPageSpeed APT repository, then install:
sudo apt-get update
sudo apt-get install nginx-module-untar
On Debian/Ubuntu, the package handles module loading automatically. No
load_moduledirective is needed.
For detailed package information, see the NGINX untar module APT page.
Configuration Reference
The NGINX untar module provides three directives. All work together: untar_archive specifies which tar file to open, untar_file specifies which file inside the archive to extract, and untar activates the handler.
untar_archive
Context: http, server, location
Default: none (required)
Specifies the path to the tar archive file. This directive accepts NGINX variables, which allows you to dynamically select archives based on the request URI.
untar_archive "$document_root/$1";
The path must point to an uncompressed .tar file. If the file does not exist, NGINX returns a 404 response.
untar_file
Context: http, server, location
Default: none (required)
Specifies the filename to extract from the archive. Like untar_archive, this directive accepts NGINX variables.
untar_file "$2";
The filename must match exactly what is stored in the tar archive, including any directory prefixes. If the file is not found in the archive, NGINX returns a 404 response.
untar
Context: location
Default: none
Activates the untar handler for the current location. This directive takes no arguments. Without it, the untar_archive and untar_file directives have no effect.
untar;
Basic Configuration Example
The most common configuration uses a regex location to extract the archive path and filename from the URI:
location ~ ^/archives/(.+?\.tar)/(.*)$ {
untar_archive "$document_root/$1";
untar_file "$2";
untar;
}
With this configuration, a request to /archives/assets.tar/css/style.css will:
- Open
/var/www/html/archives/assets.tar(assuming defaultroot) - Find
css/style.cssinside the archive - Serve it with the correct
text/csscontent type
Practical Use Cases
Distributing Software Packages
If you host downloadable software bundles, you can serve individual files from a release archive without extracting it:
server {
listen 80;
server_name downloads.example.com;
root /var/www/releases;
location ~ ^/releases/(.+?\.tar)/(.*)$ {
untar_archive "$document_root/$1";
untar_file "$2";
untar;
}
}
Users can then request https://downloads.example.com/releases/myapp-2.0.tar/README.md` to read the readme, orhttps://downloads.example.com/releases/myapp-2.0.tar/bin/myapp` to download the binary — all without you extracting the archive on disk.
Static Asset Bundles
For web applications that generate static asset bundles during CI/CD, you can deploy a single tar file instead of thousands of individual files:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# Serve assets from versioned tar bundles
location ~ ^/v(\d+)/(.*)$ {
untar_archive "$document_root/build-v$1.tar";
untar_file "$2";
untar;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
A request to /v42/js/app.js serves the file from build-v42.tar with aggressive caching headers. Deploying a new version is as simple as uploading a new tar file.
Documentation Archives
Serve versioned documentation sets from tar archives:
location ~ ^/docs/(.+?\.tar)/(.*)$ {
untar_archive /var/www/docs/$1;
untar_file $2;
untar;
add_header X-Archive-Source $1;
}
Performance Optimization
Enable File Descriptor Caching
The NGINX untar module integrates with NGINX’s open_file_cache. Enabling this cache avoids repeated open() system calls on the archive file:
server {
open_file_cache max=1000 inactive=60s;
open_file_cache_valid 30s;
open_file_cache_min_uses 1;
location ~ ^/archives/(.+?\.tar)/(.*)$ {
untar_archive "$document_root/$1";
untar_file "$2";
untar;
}
}
This is especially important when serving many requests from the same archive. Without open_file_cache, every request triggers an open() system call on the tar file. With caching enabled, the file descriptor is reused across requests.
Archive Structure Matters
The module scans the entire archive to build its index on first access. Large archives with many entries take longer to index initially. Consider these strategies:
- Keep archives focused — group related files rather than packing everything into one archive
- Minimize entry count — an archive with 100 files indexes faster than one with 10,000 files
- Use
sendfiledirective — ensuresendfile on;is set (this is NGINX’s default) to benefit from kernel-level zero-copy delivery
Memory Considerations
The archive index lives in memory for the lifetime of the NGINX worker process. Each indexed file entry consumes a small amount of memory for the filename and metadata. For archives with tens of thousands of files, monitor worker process memory usage.
SELinux Considerations
On RHEL-based systems with SELinux enforcing, you must set the correct file context on your tar archives. NGINX workers run in the httpd_t domain and can only read files labeled with httpd_sys_content_t:
sudo chcon -R -t httpd_sys_content_t /var/www/archives/
Without this, NGINX returns a 403 Forbidden error even though Unix file permissions allow access. Check the error log for “Permission denied” messages — this is almost always a SELinux context issue.
For persistent labeling that survives filesystem relabeling:
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/archives(/.*)?"
sudo restorecon -Rv /var/www/archives/
Troubleshooting
500 Internal Server Error: “Unable to read tar header”
This error means the module cannot parse the archive’s tar headers. The most common cause is using a compressed archive:
2026/02/09 23:29:15 [error] *13 Unable to read tar header "/var/www/test/compressed.tar.gz"
Solution: Use only uncompressed .tar files. Decompress before deploying:
gunzip archive.tar.gz # Produces archive.tar
bunzip2 archive.tar.bz2 # Produces archive.tar
xz -d archive.tar.xz # Produces archive.tar
404 Not Found for Files That Exist in the Archive
The filename in the request must match the archive entry exactly, including directory prefixes. Check the archive contents:
tar tf archive.tar
If the archive stores files as ./css/style.css (with ./ prefix), your untar_file value must include that prefix. Alternatively, recreate the archive without the ./ prefix:
cd /path/to/files
tar cf archive.tar css/style.css js/app.js
403 Forbidden on RHEL/CentOS
Almost always a SELinux issue. Verify with:
sudo ausearch -m avc -ts recent | grep nginx
Apply the correct context as described in the SELinux section above.
405 Method Not Allowed
The NGINX untar module only supports GET and HEAD requests. POST, PUT, DELETE, and other methods return 405. This is by design — the module serves static content from archives.
Archive Updates Not Reflected
The module’s internal cache validates against the archive’s file size and modification time. If you overwrite an archive with a file of the same size (unlikely but possible), the cache may not invalidate. Force invalidation by touching the file:
touch archive.tar
NGINX does not need to be restarted or reloaded when you update archives. The cache invalidation happens automatically on the next request.
Comparison with mod_zip
GetPageSpeed also provides the NGINX mod_zip module for working with ZIP archives. Here is when to use each:
| Feature | untar module | mod_zip |
|---|---|---|
| Archive format | .tar only |
.zip (dynamic assembly) |
| Direction | Read files from archive | Create ZIP from files |
| Use case | Serve individual files from bundles | Generate downloadable ZIP archives |
| Compression | No (uncompressed tar) | Yes (ZIP deflate) |
| Zero-copy | Yes (sendfile) | Yes (for source files) |
Use the NGINX untar module when you have pre-built tar archives and want to serve individual files. Use mod_zip when you need to dynamically assemble ZIP downloads from multiple files on disk.
Limitations
Before deploying the NGINX untar module in production, be aware of these constraints:
- No compressed archives — only plain
.tarfiles work. No.tar.gz,.tar.bz2, or.tar.xzsupport - No directory listing — you cannot list the contents of a tar archive via HTTP (for directory listing of regular files, see NGINX FancyIndex)
- Regular files only — symlinks, hard links, sparse files, and device files inside the archive are ignored
- GET and HEAD only — other HTTP methods return 405
- POSIX and GNU tar only — PAX extended headers are not supported
Conclusion
The NGINX untar module provides an efficient way to serve static files from tar archives without extraction overhead. Its zero-copy architecture and intelligent caching make it suitable for production use cases like software distribution, static asset serving, and documentation hosting.
The module is available as a pre-built package from the GetPageSpeed RPM repository for RHEL-based systems and the GetPageSpeed APT repository for Debian and Ubuntu. Source code is available on GitHub.
