Sending HTML, CSS and JavaScript uncompressed can slow page loading even when the server is not overloaded. Configuring Brotli and Gzip compression settings on Nginx, Apache or LiteSpeed can reduce transfer size and help LCP. TTFB is a related diagnostic metric, not a Core Web Vital, and aggressive dynamic compression can increase it.
In this article, we will focus on practical, real-world tuning. We will look at how compression affects Core Web Vitals, when Brotli is better than Gzip (and when it is not), and how to configure each major web server while measuring transfer savings against CPU cost. The examples cover configurations relevant to shared hosting, VPS, dedicated servers and colocation environments; which settings you can change depends on your administrative access.
How Compression Affects Core Web Vitals
Before touching configuration files, it helps to connect Brotli and Gzip to the metrics your SEO and marketing teams care about, especially Core Web Vitals. If you have not yet read it, our article Core Web Vitals and hosting: how server choices impact TTFB, LCP and CLS is a good companion to this guide.
The most important relationships:
- LCP (Largest Contentful Paint): Often depends on how quickly the HTML document and render-blocking CSS/JS arrive. Smaller transfers can help when those resources are on the critical loading path; measure the resulting LCP.
- TTFB (Time To First Byte): Compression itself does not reduce TTFB, but overly aggressive settings can increase TTFB if the server spends too long compressing each response. Good tuning is about balancing CPU cost and size savings.
- INP (Interaction to Next Paint): Compression can shorten JavaScript download time, but it does not reduce the amount of JavaScript to parse or execute. Smaller transfers alone do not establish an INP improvement.
- CLS: Compression does not directly affect layout stability. Faster CSS and font delivery alone does not guarantee fewer layout shifts.
Transfer-size savings depend on the content mix, existing compression and chosen levels. Compare compressed and uncompressed sizes for representative text responses, then measure LCP to see whether reduced transfer time improves loading on mobile connections.
Brotli vs Gzip: What You Really Need to Know
Both Brotli and Gzip compress HTTP responses and are negotiated via the Accept-Encoding and Content-Encoding headers. But there are important differences you should keep in mind when tuning your stack.
Compression efficiency and CPU cost
Brotli can produce smaller files than Gzip, especially for text-based content like HTML, CSS and JavaScript; the size and CPU trade-off depends on the content, implementation and compression level. But Brotli’s higher levels can be very CPU intensive. For dynamic responses you generate on every request, you must be conservative.
Useful mental model:
- Gzip: Nginx and Apache accept levels 1–9. A level such as 4 or 5 is a starting example to measure, not a universally optimal setting.
- Brotli: ngx_brotli and Apache mod_brotli accept quality 0–11. Start with an example such as 4 or 5 and compare size, CPU and latency. LiteSpeed/OpenLiteSpeed controls have their own scope; OpenLiteSpeed’s static-file level 0 disables Brotli.
For static files (CSS/JS built at deploy time), you can precompress with Brotli level 9–11 and store the resulting .br files on disk. The CPU cost is paid once during build, not on every request.
Browser support and HTTPS considerations
- Gzip is widely supported by desktop and mobile browsers, including many legacy clients.
- Brotli (
br) is supported by all major modern browsers, but typically only over HTTPS.
A practical negotiation strategy is:
- Make Brotli available for clients that accept it over HTTPS.
- Keep Gzip as a fallback for older or non-Brotli clients.
If you are still enabling HTTP/2 and HTTP/3 on your servers, have a look at our guide on how HTTP/2 and HTTP/3 affect SEO and Core Web Vitals. Compression, modern HTTP protocols and TLS settings work best when tuned together.
What to compress (and what not to)
Compression improves performance most when applied to text-based responses:
- HTML, JSON and XML.
- CSS and JavaScript.
- SVG and suitable uncompressed fonts such as TTF/OTF. WOFF packages font tables with optional zlib compression; WOFF2 uses Brotli. Do not add these formats to HTTP recompression lists without measuring an actual benefit.
It is usually not useful, and can waste CPU or increase transfer size, to compress already-compressed binary formats:
- JPEG, PNG, WebP, AVIF images
- MP4, WebM videos
- ZIP and similar compressed archives; PDFs may also contain compressed content, so measure any additional savings
Apply the policy to suitable responses, not every response merely because it is text. Compressing secrets together with attacker-influenced data over TLS can expose vulnerable applications to BREACH-style attacks; evaluate sensitive, personalized routes separately.
If you are still sending large unoptimized images, compression alone will not save you. Combine these settings with a proper image strategy like we described in our WebP/AVIF and image SEO guide.
Tuning Brotli and Gzip on Nginx
Nginx is very flexible for compression, but configuration can become confusing across http, server and location blocks. The following examples show a baseline configuration to adapt to your server.
Step 1: Enable modules
Most modern Nginx packages ship with Gzip support by default. Brotli may require:
- Installing an Nginx build with Brotli support, or
- Loading a Brotli dynamic module (e.g.
ngx_brotli).
Inspect the build information and the on-disk configuration separately. The commands below do not reload Nginx:
nginx -V
nginx -T
nginx -t
-V prints build parameters; it does not establish whether a separately packaged dynamic module is installed and loaded. For dynamic ngx_brotli, install modules compatible with your Nginx build and verify the filter/static load_module entries in the main context, outside http; avoid duplicate loads. -T tests and prints the configuration on disk, which may contain secrets and may differ from what existing workers loaded. Inspect it locally. After a successful -t, use your distribution’s controlled reload procedure. Related TLS guidance: TLS 1.3, OCSP stapling, HSTS preload and PFS on Nginx and Apache.
Step 2: Baseline Gzip settings
In your main Nginx config (often /etc/nginx/nginx.conf), merge the following settings into the existing http {} block. The wrapper below shows context; do not paste it inside that block:
http {
gzip on;
gzip_comp_level 4;
gzip_min_length 1024;
gzip_proxied any;
gzip_vary on;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/xhtml+xml
application/xml+rss
image/svg+xml
font/ttf
font/otf;
# ... rest of your http config ...
}
Notes:
- gzip_comp_level 4: An example starting value. Compare additional byte savings with CPU and latency before raising it.
- gzip_min_length 1024: The threshold is determined only from the response
Content-Length. It does not guarantee that every response shorter than 1024 bytes will be excluded when its length is unknown. - gzip_vary on: Enables the Accept-Encoding variation header used by the relevant Nginx compression handlers.
- gzip_proxied any: Here Nginx identifies a proxied request by its
Viarequest header;anypermits compression for these requests. Evaluate sensitive responses separately.
Step 3: Brotli settings for dynamic responses
Once Brotli is available, merge these settings into the same http block, retaining the earlier Gzip settings including gzip_vary on:
http {
# Existing gzip settings ...
brotli on;
brotli_comp_level 4;
brotli_types
text/plain
text/css
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/xhtml+xml
application/xml+rss
image/svg+xml
font/ttf
font/otf;
}
This configuration:
- Brotli quality 4 is an example to measure against CPU and transfer size.
- The prior Gzip configuration remains available for clients that accept it; a response is still subject to each handler’s eligibility checks.
- ngx_brotli also supports
brotli_min_length; like the Gzip setting, it uses a knownContent-Length. If you choose 1024, apply it in the same HTTP context and do not treat it as an unconditional cutoff for unknown-length responses.
For very busy dynamic sites, you can even start with brotli_comp_level 3 and test CPU load.
Step 4: Precompressed static assets
For a build directory you control, generate matching .br and .gz files before deployment. Install the Brotli and GNU gzip/find tools first. This example retains original files and replaces existing compressed counterparts. Each find returns a failing status if any compression invocation fails, but may process further files before returning; set -e then stops the script. Run it in the project containing dist, and deploy only after both commands succeed:
set -eu
find dist -type f \( -name '*.js' -o -name '*.css' -o -name '*.html' \) \
-exec brotli -f -q 10 {} +
find dist -type f \( -name '*.js' -o -name '*.css' -o -name '*.html' \) \
-exec gzip -f -k -9 {} +
Merge the following into the existing Nginx http block, retaining gzip_vary on. The separate ngx_http_gzip_static_module and ngx_brotli static module must be available; gzip_static is not built by default:
http {
gzip_static on; # Use file.js.gz if it exists
brotli_static on; # Use file.js.br if it exists
}
With on, the static handlers check whether the client accepts the encoding. Avoid always for this negotiation pattern. Publish the original and compressed files from the same build together; a leftover compressed counterpart may contain obsolete content. Precompression moves encoding work to build time, while request processing and delivery still have costs. Measure the actual benefit.
Step 5: Testing Nginx compression
Use real GET requests to representative eligible resources. -I sends HEAD and does not prove that a dynamic response body was compressed. Replace the example URL with your own:
curl -sS -D - -o /dev/null -H 'Accept-Encoding: gzip' https://example.com/
curl -sS -D - -o /dev/null -H 'Accept-Encoding: br' https://example.com/
curl -sS -D - -o /dev/null -H 'Accept-Encoding: identity' https://example.com/
In the response headers, confirm:
- Check status, MIME type and
Content-Encodingagainst the requested and actually eligible encoding; the identity response should remain readable without compression. - For negotiated compressed responses, inspect
Vary: Accept-Encodingand test cache variants. This header alone does not establish a CDN’s cache policy. - Headers identify the advertised encoding; verify that bodies decode correctly and compare transferred bytes with the decoded size. If a CDN is present, test its response separately from the origin.
Then run a full-page test with tools such as PageSpeed Insights or WebPageTest. As a reference, see our guide on how to properly test your website speed so you interpret the results correctly.
Tuning Brotli and Gzip on Apache (mod_deflate, mod_brotli)
Apache uses mod_deflate for Gzip and mod_brotli for Brotli. MIME filtering can be permitted in .htaccess, but compression level and Brotli window settings belong to server or virtual-host configuration.
Step 1: Enable the modules
Use your distribution’s module mechanism and existing module paths; the following server-context paths are examples, not installation commands. Check for existing loads and ensure mod_filter is also available before using AddOutputFilterByType:
LoadModule deflate_module modules/mod_deflate.so
LoadModule brotli_module modules/mod_brotli.so
Before any reload, save the previous configuration and run the distribution’s configuration test. For an httpd installation using these paths, the diagnostic is:
httpd -t
Step 2: Gzip (mod_deflate) configuration
Place this Gzip configuration in the global server configuration or a virtual host. After editing, repeat the syntax test; use the package or control panel’s supported graceful reload procedure only if that test succeeds:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain text/html text/xml text/css text/javascript application/javascript application/x-javascript application/json application/xml application/xhtml+xml application/rss+xml application/atom+xml image/svg+xml font/ttf font/otf
# Optional exclusions for already compressed request paths
SetEnvIfNoCase Request_URI "\.(?:gif|jpe?g|png|webp|avif|mp4|mp3|ogg|zip|gz|bz2|rar|woff2?)$" no-gzip
DeflateCompressionLevel 4
</IfModule>
The MIME allowlist targets suitable responses, while the optional path exclusion uses mod_setenvif; confirm that module if you retain the line. mod_deflate adds Vary: Accept-Encoding itself. Additional request-header-dependent exclusions require their own variation policy. Quality 4 is an example, not proof of lower latency on your server.
Step 3: Brotli (mod_brotli) configuration
mod_brotli is available in Apache 2.4.26 and later and must be enabled in the installed package. These quality/window directives belong to server or virtual-host configuration:
<IfModule mod_brotli.c>
BrotliCompressionQuality 4
BrotliCompressionWindow 18
AddOutputFilterByType BROTLI_COMPRESS text/plain text/html text/xml text/css text/javascript application/javascript application/json application/xml application/xhtml+xml application/rss+xml application/atom+xml image/svg+xml font/ttf font/otf
</IfModule>
BrotliCompressionWindow accepts 10–24 and represents 2 to that power bytes; the default 18 is 256 KiB. A larger value can use more memory per connection. mod_brotli adds its Accept-Encoding variation header. Having both compression modules loaded does not establish Brotli preference: inspect the effective filter chain and test br, gzip and identity requests for correct encoding without recompressing an already encoded response.
Step 4: .htaccess example
If only .htaccess is available, use MIME filtering only where the server permits it. AddOutputFilterByType requires mod_filter, the selected compression module and appropriate AllowOverride FileInfo or AllowOverrideList permission. Coordinate these examples with any existing filters:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/css application/javascript application/json image/svg+xml
</IfModule>
<IfModule mod_brotli.c>
AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json image/svg+xml
</IfModule>
DeflateCompressionLevel, BrotliCompressionQuality and BrotliCompressionWindow are server/virtual-host directives; do not put them in .htaccess. An IfModule wrapper does not grant a directive permission to run in another context.
Step 5: Testing Apache compression
Again, use curl or browser DevTools:
- Look at the Network tab, check a CSS or JS file, and verify
Content-Encodingisgziporbr. - Compare transferred bytes with the decoded resource size, then measure CPU, TTFB and loading results. Do not assume every resource will become significantly smaller.
Brotli and Gzip on LiteSpeed/OpenLiteSpeed
LiteSpeed Web Server documents compression of static and dynamic responses. OpenLiteSpeed’s panel documentation separates dynamic GZIP controls from Brotli for static files; do not assume identical behavior from similar names. The WordPress LiteSpeed Cache plugin primarily communicates application cache rules to the server cache engine.
Server-level compression settings
With authorized access to the installed product’s WebAdmin console, open its compression controls:
- LiteSpeed Web Server:
Configuration > Server > Tuning. - OpenLiteSpeed:
Server Configuration > Tuning.
Key directives:
- Enable Compression: The master switch must be enabled; set compressible MIME types and evaluate static and dynamic content separately.
- LiteSpeed Web Server: Check the dynamic compression switch, static file size bounds and the relevant static/dynamic quality controls.
- OpenLiteSpeed: Check
Enable Dynamic GZIP CompressionandGZIP Compression Level (Dynamic Content), whose range is 1–9.Brotli Compression Level (Static File)is a separate setting; 0 disables Brotli. - Adapt levels by measurement. Apply the product’s save/reload procedure and verify the resulting GET responses.
Inspect the encoding returned for clients with different Accept-Encoding values. MIME matching, response type, master switches and installed-product behavior all affect whether compression is applied.
Virtual host and context overrides
OpenLiteSpeed exposes GZIP and Brotli switches under each virtual host’s General settings. The following is a panel checklist for adjusting compression for that entire virtual host; it is not a configuration-file fragment or a directory-only exception:
- Open the intended virtual host’s General settings.
- Set Enable GZIP Compression and Enable Brotli Compression as required for that host.
- Save and follow the product’s apply procedure; verify representative GET responses.
For a download directory, prefer suitable MIME exclusions or verify the exact directory/context mechanism in the installed product. Disabling a virtual host affects more than that directory. OpenLiteSpeed’s server master switch overrides its virtual-host switches; do not expect a virtual-host override to re-enable a server-wide disabled feature.
LiteSpeed Cache plugin (WordPress)
Use LiteSpeed Cache > Cache to manage application caching where an LSCache server component is available. Do not treat Browser or Page Optimization settings as evidence that HTTP Brotli/Gzip is enabled; inspect the server’s controls and the actual response.
- Manage HTTP compression through the server configuration or hosting provider.
- Use the plugin’s documented cache and asset-optimization features for their separate purposes; installing the plugin alone does not enable server-side page caching on every web server.
- After changes, check encoding and cache behavior together, including personalized pages that must not be shared between users.
For a broader performance strategy on LiteSpeed-based hosting, see our article on speeding up WordPress with LiteSpeed Cache on shared hosting.
Practical Tuning Strategy Across All Web Servers
Regardless of whether you use Nginx, Apache or LiteSpeed, the high-level strategy is very similar. Use the following measurement-led workflow for your own configuration.
1. Prioritize the right content types
Focus on compressing:
- HTML and JSON: these control the start of rendering and data APIs.
- Critical CSS and JavaScript: anything that blocks the first render.
- SVG icons and suitable uncompressed fonts: evaluate their transfer cost; do not automatically recompress WOFF/WOFF2.
Skip or explicitly exclude:
- Images (JPEG/PNG/WebP/AVIF)
- Videos
- Archives (ZIP, GZ, RAR, etc.)
2. Choose safe compression levels
These are example values to test, not DCHost provisioning defaults or measured recommendations for your workload:
- Gzip: level 4 for dynamic content; 6–9 for precompressed static files generated at build time.
- Brotli: level 4 for dynamic; 9–11 for precompressed static assets.
Record both the baseline and changed configuration, then monitor:
- CPU usage under peak traffic.
- Average TTFB from monitoring tools.
- Error rates (e.g. timeouts if compression is too heavy for the hardware).
If CPU is underutilized, you can gently raise levels. If CPU saturates during spikes, reduce them.
3. Align compression with caching and CDN strategy
Plan compression together with cache headers and any CDN; their benefits depend on the workload and actual cache policy. For detailed header rules, see our guide to HTTP Cache-Control, ETag and CDN rules, and for the CDN concept itself, the article What is a CDN and when do you really need one.
Key alignment points:
- Cache hits: A response served completely at the CDN can avoid the corresponding origin request; cache misses and revalidation still need separate analysis.
- Vary: Retain appropriate Accept-Encoding variation and verify the CDN’s encoding/cache policy. Vary alone does not prove how a particular CDN stores variants.
- Warm-up: If you warm public cacheable pages, limit the rate and use anonymous requests; never populate shared cache with personalized session content.
4. Sync with TLS and HTTP protocol tuning
Browser Brotli support is commonly associated with HTTPS, but compression is distinct from TLS and HTTP version selection. Review the protocol configuration for the clients you support:
- Use a supported TLS policy, such as appropriately configured TLS 1.2/1.3, and test renewal.
- Evaluate HTTP/2 and HTTP/3 where supported; neither guarantees better results for every connection.
- Check certificate-specific OCSP support before enabling stapling. Current Let’s Encrypt certificates use CRL-based revocation information after the OCSP service retirement; do not assume a responder exists. Evaluate session resumption separately.
We covered these in depth in our article on TLS 1.3, OCSP stapling and modern HTTPS on Nginx and Apache. Measure each change; combining these features does not guarantee a visible Core Web Vitals improvement.
5. Measure impact on Core Web Vitals, not just transfer size
After enabling or tuning compression, measure:
- LCP: particularly on mobile connections and from key geographies where your users are.
- TTFB: ensure it does not regress due to CPU overhead.
- Total bytes transferred for HTML/CSS/JS.
Use controlled lab tests alongside available field data from PageSpeed Insights, Search Console or RUM. Keep cache state, connection profile and test locations comparable. A smaller transfer is useful only when its benefit justifies added CPU, memory and latency; no fixed percentage is required for success.
Choosing the Right Hosting Base for Brotli and Gzip
Compression is mostly a configuration issue, but hardware and hosting architecture still matter. On very weak or oversold servers, high compression levels can push CPU to 100% during traffic spikes and actually harm performance.
When evaluating hosting capacity for dynamic applications such as WordPress, WooCommerce, Laravel or Node.js, consider:
- vCPU capacity: enough headroom for PHP/Node plus Brotli/Gzip work.
- Storage latency and capacity: measure delivery of precompressed assets and allow space for originals and compressed variants; an NVMe label alone does not establish performance.
- Network throughput: so you can benefit fully from reduced payloads.
If your site is growing, it may be time to move from basic shared hosting to a VPS or even a dedicated server, where the control you receive depends on management scope, permissions, installed software and licensing. Moving plans alone does not make every example applicable. For a deeper dive into planning resources for modern PHP apps, see our guides on server-side optimization for WordPress and on NVMe VPS hosting and where the speed really comes from.
Putting It All Together
Brotli and Gzip can reduce transfer size for suitable responses, but a configuration should be judged by measured loading performance and server cost. Preserve the previous settings so that a regression can be reversed.
A practical completion checklist is:
- Confirm the installed modules, permissions and actual configuration contexts.
- Enable supported encodings for appropriate content and verify Gzip, Brotli and identity behavior; do not assume an encoding preference from module load order.
- Choose levels by transfer size, CPU and latency; generate expensive static variants during a controlled build.
- Publish matching originals and compressed variants together and check CDN/cache behavior.
- Compare LCP and TTFB with the baseline, then expand only when the observed behavior is correct.
For a DCHost plan, confirm which server settings you can manage and which are handled by the provider. Choose CPU capacity, storage and network resources around measured application demand; do not infer a particular compression setup, migration service or performance result from the plan category.
Use the guide to make one controlled change at a time: record the baseline, test the configuration, verify real responses and compare performance. Compression is one part of delivery performance; reaching good Core Web Vitals also depends on the application and front-end workload.





