<p>You don't need any fancy server trickery to make this work - As long as you don't prefix a directory with an underscore, Craft will automatically allow public routing <em>from the root</em> of your templates directory - therefore simply omit the <code>templates/</code> prefix when referencing your JS file - i.e., access it at <code>website.com/assets/js/search.js</code>.</p>

CC BY-SA 4.0
2024-11-05T16:28:03.577Z
Actually, this isn't working for me—it returns a 404 for these files. If I disable gzip compression, the files become accessible.
Romain P.
CC BY-SA 4.0
2024-11-05T18:17:57.130Z
Hm, I've tested it and it works ok for me. You probably have something else going on in your server config, or possibly there's some caching happening somewhere.
James Smith
CC BY-SA 4.0
2024-11-06T09:11:37.147Z
I tested the specified rule on a fresh project and still get a 404 Not Found, so I don’t think it’s project-specific. Oddly, the JS file is accessible directly via its URL, but including it in the page triggers a 404. The rest of my `nginx-site.conf` is from Craft CMS’s default DDEV configuration.
Romain P.
CC BY-SA 4.0
2024-11-05T15:59:42.163Z
2024-11-05T15:59:42.163Z
James Smith
<p>This issue arises in the context of a multi-site configuration in Craft CMS.</p>
<p>To properly reference the file, it’s necessary to contextualize the URL based on the current site:</p>
<pre class="lang-none prettyprint-override"><code>{% do view.registerJsFile(siteUrl('/assets/js/search.js')) %}
</code></pre>
<p>Using <code>siteUrl()</code> here ensures that the URL is constructed relative to the current site.</p>
<p>Without this adjustment, a 404 error occurred, even though the file was accessible.</p>

CC BY-SA 4.0
2024-11-06T13:40:11.087Z
2024-11-06T13:40:11.087Z
Romain P.
<p>I'm working with <strong>Craft CMS 5</strong> using a local environment configured through <strong>DDEV</strong>, which defaults to <strong>NGINX</strong>. I typically work with Apache, so I've been adjusting my caching rules for NGINX to ensure static resources like images, CSS, and JavaScript files are properly cached. Here is the configuration I’ve implemented:</p>
<pre class="lang-none prettyprint-override"><code># Enable gzip compression for common text-based content
gzip on;
gzip_types text/html text/plain text/css text/javascript application/javascript application/json application/xml font/woff font/woff2;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_vary on;

# Set cache control headers for all static assets (images, CSS, JavaScript, fonts)
location ~* \.(jpg|jpeg|png|gif|svg|css|js|woff|woff2|json)$ {
    expires 1y;
    add_header Cache-Control &quot;public, max-age=31536000, immutable&quot;;
}

# Serve /templates/assets/js/ with cache headers via proxy
location ~* ^/templates/assets/js/(.*\.js)$ {
    proxy_pass http://127.0.0.1:8080/index.php?p=assets/js/$1;
    expires 1y;
    add_header Cache-Control &quot;public, max-age=31536000, immutable&quot;;
    gzip on;
    gzip_types application/javascript;
    gzip_min_length 1024;
    gzip_comp_level 5;
    gzip_vary on;
}
</code></pre>
<h3>Problem</h3>
<p>This configuration works well for standard static assets. However, I have some <strong>JavaScript files generated dynamically through Craft CMS templates</strong>, which are served under <code>/templates/assets/js/</code>. For example, a file like <code>/templates/assets/js/search.js</code> relies on <strong>Twig</strong> templating within Craft.</p>
<p>Prior to adding this NGINX configuration, these files loaded correctly. Now, any attempt to access these JavaScript files results in <strong>404 errors</strong>, as NGINX is looking for the actual files in <code>/templates/assets/js/</code> rather than routing the requests to Craft's templating engine.</p>
<p><strong>Attempts to Solve</strong></p>
<ol>
<li>Adding specific routes in <code>config/routes.php</code> for these JavaScript files did not resolve the issue.</li>
<li>Removing or adjusting the NGINX caching rules partially fixes the problem, but I lose caching for the rest of my static resources.</li>
</ol>
<h3>Question</h3>
<p>What would be the best approach to configure NGINX to <strong>route these dynamic JavaScript files through Craft CMS</strong> without causing 404 errors, while still caching true static assets effectively?</p>
<p>Any guidance on <strong>modifying the NGINX configuration to handle these dynamic assets</strong> would be greatly appreciated. Thank you!</p>

CC BY-SA 4.0
2024-11-06T00:48:15.530Z
Worth noting that you aren't required to use the "correct" file extensions to request or send a given content type. Craft _does_ make use of extensions when rendering templates to automatically send the correct headers… but you can do that yourself using the `{% header ... %}` tag: create `/templates/assets/js/search.twig` and place `{% header 'Content-Type: text/javascript' %}` at the top!
August Miller
CC BY-SA 4.0
2024-11-06T00:49:18.710Z
Additionally, this sounds a lot like what the [`try_files`](https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files) directive is for… When using regular expressions in `location` rules, the order of the rules also matters!
August Miller
<cache><javascript><nginx><ddev><craft-cms>
NGINX Cache Configuration Causing 404 Errors for Dynamic JavaScript Files in Craft CMS 5
# NGINX Cache Configuration Causing 404 Errors for Dynamic JavaScript Files in Craft CMS 5

(Asked by: username_0 on 2024-11-05)

I'm working with Craft CMS 5 using a local environment configured through DDEV, which defaults to NGINX. I typically work with Apache, so I've been adjusting my caching rules for NGINX to ensure static resources like images, CSS, and JavaScript files are properly cached. Here is the configuration I’ve implemented:
# Enable gzip compression for common text-based content
gzip on;
gzip_types text/html text/plain text/css text/javascript application/javascript application/json application/xml font/woff font/woff2;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_vary on;

# Set cache control headers for all static assets (images, CSS, JavaScript, fonts)
location ~* \.(jpg|jpeg|png|gif|svg|css|js|woff|woff2|json)$ {
    expires 1y;
    add_header Cache-Control "public, max-age=31536000, immutable";
}

# Serve /templates/assets/js/ with cache headers via proxy
location ~* ^/templates/assets/js/(.*\.js)$ {
    proxy_pass http://127.0.0.1:8080/index.php?p=assets/js/$1;
    expires 1y;
    add_header Cache-Control "public, max-age=31536000, immutable";
    gzip on;
    gzip_types application/javascript;
    gzip_min_length 1024;
    gzip_comp_level 5;
    gzip_vary on;
}

Problem
This configuration works well for standard static assets. However, I have some JavaScript files generated dynamically through Craft CMS templates, which are served under /templates/assets/js/. For example, a file like /templates/assets/js/search.js relies on Twig templating within Craft.
Prior to adding this NGINX configuration, these files loaded correctly. Now, any attempt to access these JavaScript files results in 404 errors, as NGINX is looking for the actual files in /templates/assets/js/ rather than routing the requests to Craft's templating engine.
Attempts to Solve

Adding specific routes in config/routes.php for these JavaScript files did not resolve the issue.
Removing or adjusting the NGINX caching rules partially fixes the problem, but I lose caching for the rest of my static resources.

Question
What would be the best approach to configure NGINX to route these dynamic JavaScript files through Craft CMS without causing 404 errors, while still caching true static assets effectively?
Any guidance on modifying the NGINX configuration to handle these dynamic assets would be greatly appreciated. Thank you!

**Tags:** cache, javascript, nginx, ddev, craft-cms

> **Comments:**
> **username_1**: Worth noting that you aren't required to use the "correct" file extensions to request or send a given content type. Craft _does_ make use of extensions when rendering templates to automatically send the correct headers… but you can do that yourself using the `{% header ... %}` tag: create `/templates/assets/js/search.twig` and place `{% header 'Content-Type: text/javascript' %}` at the top!  
> **username_1**: Additionally, this sounds a lot like what the [`try_files`](https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files) directive is for… When using regular expressions in `location` rules, the order of the rules also matters!  

---

## 2 answers

### Answer by username_2 on 2024-11-05. Score: 0

You don't need any fancy server trickery to make this work - As long as you don't prefix a directory with an underscore, Craft will automatically allow public routing *from the root* of your templates directory - therefore simply omit the `templates/` prefix when referencing your JS file - i.e., access it at `website.com/assets/js/search.js`.

> **Comments:**
> **username_0**: Actually, this isn't working for me—it returns a 404 for these files. If I disable gzip compression, the files become accessible.  
> **username_2**: Hm, I've tested it and it works ok for me. You probably have something else going on in your server config, or possibly there's some caching happening somewhere.  
> **username_0**: I tested the specified rule on a fresh project and still get a 404 Not Found, so I don’t think it’s project-specific. Oddly, the JS file is accessible directly via its URL, but including it in the page triggers a 404. The rest of my `nginx-site.conf` is from Craft CMS’s default DDEV configuration.  

---

### Answer by username_0 on 2024-11-06. Score: 0

This issue arises in the context of a multi-site configuration in Craft CMS.
To properly reference the file, it’s necessary to contextualize the URL based on the current site:
{% do view.registerJsFile(siteUrl('/assets/js/search.js')) %}

Using siteUrl() here ensures that the URL is constructed relative to the current site.
Without this adjustment, a 404 error occurred, even though the file was accessible.


---

