> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Compression

> Demonstrates enabling gzip in Nginx reverse proxy, measuring transfer improvements with enlarged images and verifying compression via browser devtools and curl.

In this lesson we'll enable gzip compression on an Nginx reverse proxy and compare resource transfer times. Workflow:

* Measure transfers with compression disabled.
* Artificially enlarge JPEGs on the backends so differences are visible.
* Enable gzip in Nginx, reload, and re-measure.
* Verify results in the browser devtools and via curl.

Initial test topology: browser → Nginx (no compression) → two Apache backend servers.

![A simple diagram showing a browser (with a loading spinner and a CSS file) sending requests to an NGINX reverse proxy labeled "No Compression," which forwards traffic to two Apache web servers.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Demo-Compression/browser-nginx-no-compression-apache-servers.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=721da8353919ec4ce14f922a832dafe8)

Images (JPEG/PNG/WebP, etc.) are generally already compressed. Proxy compression is most effective for text-based assets (HTML, CSS, JS, JSON, XML). This demo deliberately enlarges JPEGs to 20 MB so the gzip effect is clearly visible.

## Step 1 — Enlarge JPEGs on the backend

Make the images large enough to produce measurable transfer times.

Commands (run on each backend serving the site, e.g., node01 and node02):

```bash theme={null}
# on node01 (Apache backend)
cd /var/www/html/images/
ll
```

Sample directory listing (trimmed):

```text theme={null}
total 136
-rw-r--r-- 1 root root 1259 Feb 17 20:31 logo.svg
-rw-r--r-- 1 root root 6311 Feb 17 20:31 pic01.jpg
...
-rw-r--r-- 1 root root 17129 Feb 17 20:31 pic13.jpg
```

Enlarge all JPEGs to 20 MB:

```bash theme={null}
for file in *.jpg; do
  fallocate -l 20M "$file"
done
```

Repeat the same on the second backend (node02) if applicable.

## Step 2 — Monitor backend access logs

While you load the site from the browser, watch the Apache access log to confirm requests reach the backend:

```bash theme={null}
# on node01
tail -f /var/log/apache2/access.log
```

Example log line:

```text theme={null}
example.com:443 127.0.0.1 - - [17/Feb/2025:20:32:46 +0000] "GET / HTTP/1.1" 200 11242 "-" "curl/7.81.0"
```

## Step 3 — Inspect the site without compression

Open your browser developer tools (Network tab) and load the page. You should see transfers matching the enlarged file size (\~20 MB). Example: the devtools Network panel showing GET requests, statuses and transfer sizes:

![A browser window showing a webpage titled "Generic Page" with the devtools Network panel open. The Network panel lists GET requests, statuses, file types and transfer sizes for the page's resources.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Demo-Compression/browser-devtools-network-requests.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=a556b31ff6257a272d288ca73e2f3b37)

A representative response header for a large JPEG when gzip is disabled:

```http theme={null}
GET /images/pic01.jpg HTTP/1.1
Host: 443-port-ndovbd35ytlrupmo.kk-lab-dev.kodekloud.com

HTTP/1.1 200 OK
Accept-Ranges: bytes
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Length: 20971520
Content-Security-Policy: default-src 'self'
Content-Type: image/jpeg
Date: Mon, 17 Feb 2025 20:56:45 GMT
Etag: "1400000-62e5cbe7aae75"
Last-Modified: Mon, 17 Feb 2025 20:55:27 GMT
Referrer-Policy: origin
Server: Google Frontend
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Via: 1.1 google
X-Frame-Options: SAMEORIGIN
```

Notes:

* There is no `Content-Encoding` header.
* `Content-Length` equals the full (enlarged) file size.

## Step 4 — Enable gzip in Nginx

Edit your global Nginx configuration (e.g., `nginx.conf`) or the `http { ... }` section and add gzip directives. Key settings:

```nginx theme={null}
# Gzip Settings (add to http { ... } or main nginx.conf)
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types
    text/plain
    text/css
    application/json
    application/javascript
    text/xml
    application/xml
    application/xml+rss
    text/javascript
    image/jpeg;
```

Important directive purposes:

| Directive | Purpose |
| - | - |
| `gzip on;` | Enable gzip compression globally. |
| `gzip_vary on;` | Add `Vary: Accept-Encoding` so caches know responses vary by encoding. |
| `gzip_proxied any;` | Compress responses even when Nginx is acting as a reverse proxy. |
| `gzip_comp_level 6;` | Compression level (tradeoff CPU vs size). |
| `gzip_buffers 16 8k;` | Buffering configuration for compression output. |
| `gzip_http_version 1.1;` | Minimum HTTP version required to use gzip. |
| `gzip_types ...` | MIME types to compress; adding `image/jpeg` is unusual in production but included here for demo purposes. |

Do not enable gzip for image formats in production unless you know the files are not already compressed. Compressing already-compressed binary formats usually wastes CPU with little size benefit. This demo includes `image/jpeg` only to show the effect with artificially enlarged images.

Test and reload Nginx after saving:

```bash theme={null}
nginx -t
sudo systemctl restart nginx
```

## Step 5 — Verify compression from the browser and CLI

* Open a new private/incognito window to avoid cached responses.
* Reload the page and inspect the Network panel. Compressed responses show `Content-Encoding: gzip` and a smaller "Transferred" size. Load times for large assets typically drop from seconds to milliseconds.

You can also check response headers from the command line:

```bash theme={null}
curl -sI -H "Accept-Encoding: gzip,deflate" "https://example.com/images/pic04.jpg"
```

Expected headers after enabling gzip (note `Content-Encoding: gzip` and `Vary: Accept-Encoding`):

```http theme={null}
HTTP/1.1 200 OK
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
Content-Encoding: gzip
Content-Security-Policy: default-src 'self'
Content-Type: image/jpeg
Date: Mon, 17 Feb 2025 21:03:05 GMT
Etag: W/"1400000-62e5cbe7acdb5"
Last-Modified: Mon, 17 Feb 2025 20:55:27 GMT
Referrer-Policy: origin
Server: Google Frontend
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Vary: Accept-Encoding
Via: 1.1 google
X-Frame-Options: SAMEORIGIN
```

Browser devtools will show the smaller "Transferred" size, indicating the over-the-wire payload was reduced.

## Step 6 — Example minimal server block used in the demo

This example shows a minimal HTTPS server block with a proxied upstream. Headers, cache and rate limiting are included where relevant for the demo:

```nginx theme={null}
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/ssl/certs/example.com.pem;
    ssl_certificate_key /etc/ssl/certs/example.com-key.pem;

    root /var/www/html;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
    add_header X-Frame-Options "SAMEORIGIN";
    add_header Content-Security-Policy "default-src 'self'";
    add_header Referrer-Policy origin;
    add_header Cache-Control "public, max-age=3600";

    index index.html index.htm index.nginx-debian.html;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Proxy-Cache $upstream_cache_status;
        proxy_cache app_cache;
        limit_req zone=req_limit_per_ip;
        proxy_pass https://example;
    }

    location /admin {
        auth_basic "Restricted Access";
        auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
    }
}
```

## Step 7 — Example consolidated global nginx.conf snippets

A compact example showing recommended global settings (including gzip) used during this demo:

```nginx theme={null}
events {
    worker_connections 768;
}

http {
    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=1000r/m;
    limit_req_status 429;

    proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=app_cache:10m;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_valid 200 302 10m;
    proxy_cache_valid 404 1m;

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        application/xml
        application/xml+rss
        text/javascript
        image/jpeg;
}
```

## References

For more detail on HTTP headers and which ones to add for security and caching, see MDN's HTTP headers documentation:

* [MDN's HTTP headers documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)

![A web browser window open to the MDN Web Docs page titled "HTTP headers," showing the article content in the center with navigation menus on the left and a table of contents on the right. The browser has several tabs and a dark green theme at the top.](https://mintcdn.com/kodekloud-c4ac6d9a/ij3FNIPjp1w0Myd0/images/Nginx-for-Beginners/Performance/Demo-Compression/mdn-http-headers-browser-window.jpg?fit=max\&auto=format\&n=ij3FNIPjp1w0Myd0\&q=85\&s=9962bd519cbe51888b32e9295bd7bae6)

That concludes the compression demo. Best practice: enable gzip for text-based assets by default; only compress already-compressed binary formats in controlled scenarios after testing.

> **[Watch Video](https://learn.kodekloud.com/user/courses/nginx-for-beginners/module/4a5db5c4-df5f-4291-84f0-013d1c4ce235/lesson/ab86ef5a-e11e-439b-9dbe-6aa962facf7b)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/nginx-for-beginners/module/4a5db5c4-df5f-4291-84f0-013d1c4ce235/lesson/a5e800f9-add5-4f9d-9970-e3d9dfed2b9e)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.