Nginx Gzip NGINX

May 3rd, 2019 - written by Kimserey with .

When building single page applications, like Angular applications, where the entire application is sent over HTTP, compressing static files before serving them can provide a major boost in performance, drastically reducing latency. One of the most common compression algorithm widely supported by reverse proxies and browsers is Gzip. Today we will see how we can enable gzip compression on Nginx.

Example

Let’s take for example a website composed by 3 files:

1
2
3
4
5
/index.html
/bootstrap.min.js
/bootstrap.min.css
/popper.min.js
/jquery-3.3.1.slim.min.js

The index file references bootstrap css, bootstrap js and its dependencies and shows a Hello world message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html>

<head>
	<link href="bootstrap.min.css" rel="stylesheet">
	<script src="jquery-3.3.1.slim.min.js"></script>
	<script src="popper.min.js"></script>
	<script src="bootstrap.min.js"></script>
</head>

<body>

	<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
		Launch Hello World
	</button>

	<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
		<div class="modal-dialog" role="document">
			<div class="modal-content">
				<div class="modal-header">
					<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
					<button type="button" class="close" data-dismiss="modal" aria-label="Close">
						<span aria-hidden="true">&times;</span>
					</button>
				</div>
				<div class="modal-body">
					Hello World
				</div>
				<div class="modal-footer">
					<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
					<button type="button" class="btn btn-primary">Save changes</button>
				</div>
			</div>
		</div>
	</div>

</body>

</html>

Then in our nginx server configuration, we serve the current location which contains our index.html.

1
2
3
4
5
6
7
8
server {                                                                          
  listen       8080;                                                              
  server_name  localhost;                                                                                  
                                                                                
  location / {                                                                  
      root   /usr/share/nginx/html;                                             
  }                                                                             
}   

If you never seen nginx, you can refer to my previous post where I describe briefly how to setup nginx on Ubuntu.

Once we start nginx, we can navigate to our website and if we look in chrome debugger on the Network tab, we should see the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Response Headers:

HTTP/1.1 200 OK
Server: nginx/1.15.5
Date: Mon, 15 Oct 2018 08:40:21 GMT
Content-Type: text/css
Content-Length: 140936
Last-Modified: Sun, 14 Oct 2018 18:24:30 GMT
Connection: keep-alive
ETag: "5bc389de-22688"
Accept-Ranges: bytes

Request Headers:

GET /bootstrap.min.css HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Accept: text/css,*/*;q=0.1
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Cookie: jenkins-timestamper-offset=-3600000

What we see here is that the request accepts gzip endcoding Accept-Encoding: gzip but the response is not gzip’d. We also can see the following size files:

     
localhost 1.4 KB 70 ms
bootstrap.min.css 138 KB 56 ms
jquery-3.3.1.slim.min.js 68.5 KB 38 ms
popper.min.js 20.1 KB 79 ms
bootstrap.min.js 50.1 KB 103 ms

Enable Gzip

Gzip module documentation can be found on nginx documentation. To enable it, we place the following directives under either http, server or location:

1
2
gzip on;
gzip_types application/javascript image/* text/css;

Here we place it under server:

1
2
3
4
5
6
7
8
9
10
server {                                                                          
  listen       8080;                                                              
  server_name  localhost;         
  gzip on;
  gzip_types application/javascript image/* text/css;

  location / {                                                                  
      root   /usr/share/nginx/html;                                             
  }                                                                             
}  

By default, the gzip_types is only text/html therefore here we change it to gzip css, js and images. Once we restart nginx, we can now observe the following:

1
2
3
4
5
6
7
8
9
10
11
Response Headers:

HTTP/1.1 200 OK
Server: nginx/1.15.5
Date: Mon, 15 Oct 2018 08:51:15 GMT
Content-Type: text/css
Last-Modified: Sun, 14 Oct 2018 18:24:30 GMT
Transfer-Encoding: chunked
Connection: keep-alive
ETag: W/"5bc389de-22688"
Content-Encoding: gzip

The response now contains the encoding Content-Encoding: gzip. And the following sizes:

     
localhost 749 B 63 ms
bootstrap.min.css 27.8 KB 19 ms
jquery-3.3.1.slim.min.js 27.6 KB 37 ms
popper.min.js 8.1 KB 77 ms
bootstrap.min.js 17.0 KB 82 ms

As we can observe, the js and css files size are very much reduced. As we can imagine, for SPA like Angular application where we use component libraries, we can get a lot of performance boost out of gzip.

Nginx Docker Container

As an extra, we will see how we can test nginx on Windows by starting it in a Docker container. We start first by creating a Dockerfile which will start from nginx and will copy the current directory into /usr/share/nginx/html directory.

1
2
FROM nginx
COPY . /usr/share/nginx/html

Then we create a nginx.conf file which will replace the default nginx.conf.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
user  nginx;                                                                        
worker_processes  1;                                                                
                                                                                    
error_log  /var/log/nginx/error.log warn;                                           
pid        /var/run/nginx.pid;                                                      
                                                                                    
                                                                                    
events {                                                                            
    worker_connections  1024;                                                       
}                                                                                   
                                                                                    
                                                                                    
http {                                                                              
    include       /etc/nginx/mime.types;                                            
    default_type  application/octet-stream;                                         
                                                                                    
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '       
                      '$status $body_bytes_sent "$http_referer" '                   
                      '"$http_user_agent" "$http_x_forwarded_for"';                 
                                                                                    
    access_log  /var/log/nginx/access.log  main;                                    
                                                                                    
    sendfile        on;                                                             
                                                                                    
    keepalive_timeout  65;                                                          

    server {                                                                          
      listen       80;                                                              
      server_name  localhost;           
      gzip  on;      
      gzip_types application/javascript image/* text/css;                                                                                                           
                                                                                    
      location / {                                                                  
          root   /usr/share/nginx/html;                                             
      }                                                                             
    }                                                
}

To get that file, I copied it from the default file present in the image. Then we build the image naming it nginx-test:

1
docker build -t nginx-test .

Lastly we run the container:

1
docker run --name nginx-test -d -p 8080:80 -v c:/Projects/nginx-test/nginx.conf:/etc/nginx/nginx.conf:ro nginx-test

And we should now be able to test that our files are well gzip’d when we navigate to localhost:8080!

Conclusion

Today we saw how to enable gzip on nginx. We started by looking into an example with the default behavior where gzip is disabled. Next we enabled it and look into the performance benefits from it and lastly as extra, we look into how we could test nginx in a Docker container so that we could run test in a sandbox. Hope you liked this post, see you next time!

Designed, built and maintained by Kimserey Lam.