How to Add Expires Headers

How to Add Expires Headers in Nginx because when I add it, nginx does not start

My code is

location ~* \.(jpg|jpeg|gif|png|svg)$ {
  expires 365d;
}
 
location ~* \.(pdf|css|html|js|swf)$ {
  expires 3d;
}
                location ~* ^.+\.(ogg|ogv|svg|svgz|swf|eot|otf|woff|woff2|mov|mp3|mp4|webm|flv|ttf|rss|atom|webp|gif|ico|bmp|mid|midi|wav|r>
                        expires 30d;
                        fastcgi_hide_header "Set-Cookie";
                }

Should work fine

I don’t know if I’m wrong in adding this file to the Nginx configuration, because it keeps disconnecting Nginx when I restart the file and adding it outside settings the http { }

It should be inside the

server {

}

Block for each template

And am I editing the right file? /etc/nginx/nginx.conf

Because I only have such configurations

# Server globals
user                 www-data;
worker_processes     auto;
worker_rlimit_nofile 65535;
error_log            /var/log/nginx/error.log;
pid                  /run/nginx.pid;
include              /etc/nginx/conf.d/main/*.conf;
include              /etc/nginx/modules-enabled/*.conf;

# Worker config
events {
	worker_connections 1024;
	use                epoll;
	multi_accept       on;
}

http {
	# Main settings
	sendfile                        on;
	tcp_nopush                      on;
	tcp_nodelay                     on;
	client_header_timeout           180s;
	client_body_timeout             180s;
	client_header_buffer_size       2k;
	client_body_buffer_size         256k;
	client_max_body_size            1024m;
	large_client_header_buffers     4 8k;
	send_timeout                    60s;
	keepalive_timeout               30s;
	keepalive_requests              1000;
	reset_timedout_connection       on;
	server_tokens                   off;
	server_name_in_redirect         off;
	server_names_hash_max_size      512;
	server_names_hash_bucket_size   512;
	charset                         utf-8;
	# FastCGI settings
	fastcgi_buffers                 512 4k;
	fastcgi_buffer_size             256k;
	fastcgi_busy_buffers_size       256k;
	fastcgi_temp_file_write_size    256k;
	fastcgi_connect_timeout         30s;
	fastcgi_read_timeout            300s;
	fastcgi_send_timeout            180s;
	fastcgi_cache_lock              on;
	fastcgi_cache_lock_timeout      5s;
	fastcgi_cache_background_update on;
	fastcgi_cache_revalidate        on;
	# Proxy settings
	proxy_redirect                  off;
	proxy_set_header                Host $host;
	proxy_set_header                Early-Data $rfc_early_data;
	proxy_set_header                X-Real-IP $remote_addr;
	proxy_set_header                X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_pass_header               Set-Cookie;
	proxy_buffers                   256 4k;
	proxy_buffer_size               32k;
	proxy_busy_buffers_size         32k;
	proxy_temp_file_write_size      256k;
	proxy_connect_timeout           30s;
	proxy_read_timeout              300s;
	proxy_send_timeout              180s;
	# Log format
	log_format                      main '$remote_addr - $remote_user [$time_local] $request "$status" $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
	log_format                      bytes '$body_bytes_sent';
	log_not_found                   off;
	access_log                      off;
	# Mime settings
	include                         /etc/nginx/mime.types;
	default_type                    application/octet-stream;
	# Compression
	gzip                            on;
	gzip_vary                       on;
	gzip_static                     on;
	gzip_comp_level                 6;
	gzip_min_length                 1024;
	gzip_buffers                    128 4k;
	gzip_http_version               1.1;
	gzip_types                      text/css text/javascript text/js text/plain text/richtext text/shtml text/x-component text/x-java-source text/x-markdown text/x-script text/xml image/bmp image/svg+xml image/vnd.microsoft.icon image/x-icon font/otf font/ttf font/x-woff multipart/bag multipart/mixed application/eot application/font application/font-sfnt application/font-woff application/javascript application/javascript-binast application/json application/ld+json application/manifest+json application/opentype application/otf application/rss+xml application/ttf application/truetype application/vnd.api+json application/vnd.ms-fontobject application/wasm application/xhtml+xml application/xml application/xml+rss application/x-httpd-cgi application/x-javascript application/x-opentype application/x-otf application/x-perl application/x-protobuf application/x-ttf;
	gzip_proxied                    any;
	# Cloudflare IPs
	include                         /etc/nginx/conf.d/cloudflare.inc;
	# SSL PCI compliance
	ssl_buffer_size                 1369;
	ssl_ciphers                     "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-SHA256";
	ssl_dhparam                     /etc/ssl/dhparam.pem;
	ssl_early_data                  on;
	ssl_ecdh_curve                  auto;
	ssl_prefer_server_ciphers       on;
	ssl_protocols                   TLSv1.2 TLSv1.3;
	ssl_session_cache               shared:SSL:20m;
	ssl_session_tickets             on;
	ssl_session_timeout             7d;
	resolver                        213.186.33.99 valid=300s ipv6=off;
	resolver_timeout                5s;
	# Error pages
	error_page                      403 /error/404.html;
	error_page                      404 /error/404.html;
	error_page                      410 /error/410.html;
	error_page                      500 501 502 503 504 505 /error/50x.html;
	# Proxy cache
	proxy_cache_path                /var/cache/nginx levels=2 keys_zone=cache:10m inactive=60m max_size=1024m;
	proxy_cache_key                 "$scheme$request_method$host$request_uri";
	proxy_temp_path                 /var/cache/nginx/temp;
	proxy_ignore_headers            Cache-Control Expires;
	proxy_cache_use_stale           error timeout invalid_header updating http_502;
	proxy_cache_valid               any 1d;
	# FastCGI cache
	fastcgi_cache_path              /var/cache/nginx/micro levels=1:2 keys_zone=microcache:10m inactive=30m max_size=1024m;
	fastcgi_cache_key               "$scheme$request_method$host$request_uri";
	fastcgi_ignore_headers          Cache-Control Expires Set-Cookie;
	fastcgi_cache_use_stale         error timeout invalid_header updating http_500 http_503;
	add_header                      X-FastCGI-Cache $upstream_cache_status;

	# Cache bypass
	map $http_cookie $no_cache {
		default              0;
		~SESS                1;
		~wordpress_logged_in 1;
	}

	# File cache (static assets)
	open_file_cache                 max=10000 inactive=30s;
	open_file_cache_valid           60s;
	open_file_cache_min_uses        2;
	open_file_cache_errors          off;
	# Wildcard include
	include                         /etc/nginx/conf.d/*.conf;
	include                         /etc/nginx/conf.d/domains/*.conf;
}

You need to update the website templates

And where can I find them?

Best way to add custom headers or any other headers to a site in Nginx is by copying the template you are using and modify the included expire headers. Make sure to copy both the .tpl and .stpl files and modify headers on both.

The template files vary depending on your setup. Here is the documentation for reference Web Templates and FastCGI/Proxy Cache | Hestia Control Panel

Whatever new file name your template has its what it would show in Hestia’s control panel setting. Simply select that template under each site and you are good to go.

For example, I copied the wordpress.tpl and wordpress.stpl files and named them wordpress-7g.tpl and wordpress-7g.stpl. Under advance options for the site, it shows as “wordpress-7g”.

Hope that helps.

1 Like

Damn, it still doesn’t work, I added it as written in the default template but when I check in the browser it says something like Expires: Wed, 11 Jan 1984 05:00:00 GMT and that’s not how it’s supposed to be, it should write the date 30 days

One thing I forgot to mentioned, I think you need to rebuild the site(s) for the template to take over.

What do you mean rebuild?. I created a new template by copying the default and did so with 2 files, then embedded this script

location ~* ^.+\.(ogg|ogv|svg|svgz|swf|eot|otf|jpg|jpeg|png|woff|woff2|mov|mp3|mp4|webm|flv|ttf|rss|atom|webp|gif|ico|bmp|mid|midi|wav)$ {
                        expires 30d;
                }

But the search engine still shows it to me

“Expires: Wed, 11 Jan 1984 05:00:00 GMT”

I posted a screenshot that shows the actions dropdown. After you selected your template, you need to select the site and then under the actions dropdown select “Rebuild” and click the right blue arrow. That will rebuild the site’s configuration files to use the new template.

1 Like

OK, I chose the domain to be rebuilt, I did it as you showed, but I still have the following text: my entire wordpress.tpl file looks like this

My wordpress.tpl file

#=========================================================================#
# Default Web Domain Template                                             #
# DO NOT MODIFY THIS FILE! CHANGES WILL BE LOST WHEN REBUILDING DOMAINS   #
# https://hestiacp.com/docs/server-administration/web-templates.html      #
#=========================================================================#

server {
        listen      %ip%:%proxy_port%;
        server_name %domain_idn% %alias_idn%;
        error_log   /var/log/%web_system%/domains/%domain%.error.log error;

        include %home%/%user%/conf/web/%domain%/nginx.forcessl.conf*;

        location ~ /\.(?!well-known\/|file) {
                deny all;
                return 404;
        }

        location / {
                proxy_pass http://%ip%:%web_port%;

                location ~* ^.+\.(%proxy_extensions%)$ {
                        try_files  $uri @fallback;

                        root       %docroot%;
                        access_log /var/log/%web_system%/domains/%domain%.log combined;
                        access_log /var/log/%web_system%/domains/%domain%.bytes bytes;
                        }
        }

        location ~* ^.+\.(ogg|ogv|svg|svgz|swf|eot|otf|jpg|jpeg|png|woff|woff2|mov|mp3|mp4|webm|flv|ttf|rss|atom|webp|gif|ico|bmp|mid|midi|wav)$ {
                        expires 30d;
                        add_header Cache-Control "public";
                }


        location @fallback {
                proxy_pass http://%ip%:%web_port%;
        }

        location /error/ {
                alias %home%/%user%/web/%domain%/document_errors/;
        }

        include %home%/%user%/conf/web/%domain%/nginx.conf_*;
}

A few things to troubleshoot:

1- Did you duplicated the wordpress.tpl AND .stpl files with a new name?
2- Did you added the modifications to both files?
3- Did you selected this new template under the advance options “Web Template” dropdown?
4- Did you rebuild the site after doing all these?

If you answer yes to ALL those questions then the only think I could think is network caching. Whatever tool you are using to test those headers is caching and hasn’t picked up the new configurations.

My answer is

  1. Yes, I copied the files as they should be
  2. Yes, I modified these two files as they should be
  3. Yes, I chose the new template that I created
  4. This is how I rebuilt the house where I chose it

And it should show up according to the new template

Create a file nginx.conf_whatever

And place it in the folder included.

Ta da!