Answers.Body: <p><a href="https://github.com/nystudio107/nginx-craft" rel="noreferrer">Nginx-Craft</a> has an example setup that does this:</p>
  
  <p><a href="https://github.com/nystudio107/nginx-craft/blob/master/sites-available/somedomain.com.conf#L60" rel="noreferrer">https://github.com/nystudio107/nginx-craft/blob/master/sites-available/somedomain.com.conf#L60</a></p>
  
  <pre><code># 301 Redirect URLs with trailing /'s as per https://webmasters.googleblog.com/2010/04/to-slash-or-not-to-slash.html
  rewrite ^/(.*)/$ /$1 permanent;
  </code></pre>
  
  <p>This is working on the nystudio107.com site, if you go here:</p>
  
  <p><a href="https://nystudio107.com/blog/" rel="noreferrer">https://nystudio107.com/blog/</a></p>
  
  <p>...the redirected URL will be this:</p>
  
  <p><a href="https://nystudio107.com/blog" rel="noreferrer">https://nystudio107.com/blog</a></p>
  
  <p>Or am I missing something?</p>
  
  <pre><code>andrew@kotak ~ $ curl -I https://nystudio107.com/blog/
  HTTP/1.1 301 Moved Permanently
  Server: nginx/1.13.6
  Date: Thu, 15 Feb 2018 19:39:49 GMT
  Content-Type: text/html
  Location: https://nystudio107.com/blog
  Connection: keep-alive
  Set-Cookie: abtest=green;Path=/;Max-Age=86400;secure; SameSite=strict
  Strict-Transport-Security: max-age=15768000; includeSubDomains; preload
  X-Frame-Options: SAMEORIGIN
  X-XSS-Protection: 1; mode=block
  X-Content-Type-Options: nosniff
  Referrer-Policy: no-referrer-when-downgrade
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-15T19:50:52.120Z
Answers.Text: Ah! I totally misread that in the example. I'm trying to add trailing slashes, not remove them. Fast response! I've also amended the question/answer. The one thing I still run into is query strings on slashed paths, ie domain.com/path?query=string has issues, whereas domain.com/path/?query=string is fine. Any insight?
Answers.UserDisplayName: hisnameisjimmy
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-15T23:29:39.420Z
Answers.Text: Nvm, figured it out!
Answers.UserDisplayName: hisnameisjimmy
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-15T23:56:22.707Z
Answers.Text: Only heretics add slashes. We remove them 
Answers.UserDisplayName: andrew.welch
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-15T19:37:28.583Z
Answers.LastActivityDate: 2018-02-15T19:37:28.583Z
Answers.UserDisplayName: andrew.welch
Answers.Body: <p>After some digging, there appear to be two ways that avoid hitting the admin and url query strings.</p>
  
  <p>The first, (and apparently better one, as '<a href="https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/" rel="nofollow noreferrer">if is evil</a>' according to nginx) uses location handlers:</p>
  
  <pre><code># 301 Redirect for trailing slash
  location ~ ^([^.\?]*[^/])$ {
    try_files $uri @addslash;
  }
  
  # 301 Redirect for trailing slash
  location @addslash {
    return 301 $uri/$is_args$args;
  }
  
  # Root directory location handler
  location / {
      try_files $uri/index.html $uri $uri/ /index.php?$query_string;
  }
  </code></pre>
  
  <p>The second, more evil one that uses an if statement:</p>
  
  <pre><code>if ($request_uri !~ "^/admin")
  {
      rewrite ^([^.\?]*[^/])$ $1/$is_args$args permanent;
  }
  </code></pre>
  
  <p>I included the context of the root location handler in the first solution so that you can combine it with your existing root location handling setup. I'm currently leaning on a lot of NYStudio's work (a truly incredible contributor to the open source ecosystem of Craft) with FastCGI, location handlers for foreign languages, etc and both of these solutions work with it. </p>
  
  <p>The first also works with query strings, if a user visits a URL either with or without a trailing slash. For example:</p>
  
  <ul>
  <li>This: www.domain.com/page?string=234</li>
  <li>Will go to this: www.domain.com/page/?string=234</li>
  <li>And this: www.domain.com/page</li>
  <li>Will go to this: www.domain.com/page/</li>
  </ul>
  
  <p>Interestingly, if you use query_string instead of is_args for the return url, it will rewrite it wrong. Only is_args worked in my experience. </p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-02-15T19:27:16.200Z
Answers.LastActivityDate: 2018-02-15T23:23:34.967Z
Answers.LastEditDate: 2018-02-15T23:23:34.967Z
Answers.UserDisplayName: hisnameisjimmy
Body: <p>What's the best way to redirect to a trailing slash in Nginx with Craft CMS? I've seen some advice for Apache .htaccess, etc, but not Nginx. For those curious, here's why I might want to do this: <a href="https://webmasters.googleblog.com/2010/04/to-slash-or-not-to-slash.html" rel="nofollow noreferrer">To slash or not to slash</a>.</p>
  
  <p><a href="https://nystudio107.com/" rel="nofollow noreferrer">NYStudio107</a> <a href="https://github.com/nystudio107/nginx-craft" rel="nofollow noreferrer">recommendations</a> advise removing the trailing slash, but since we were formerly on Wordpress and had a trailing slash to begin with, I want to be consistent with the past history in Google Analytics.</p>
  
Tags: <redirect><nginx>
Title: Trailing slashes with Nginx and Craft
ThreadText: # Trailing slashes with Nginx and Craft
  
  (Asked by: username_0 on 2018-02-15)
  
  What's the best way to redirect to a trailing slash in Nginx with Craft CMS? I've seen some advice for Apache .htaccess, etc, but not Nginx. For those curious, here's why I might want to do this: [To slash or not to slash](https://webmasters.googleblog.com/2010/04/to-slash-or-not-to-slash.html).
  
  [NYStudio107](https://nystudio107.com/) [recommendations](https://github.com/nystudio107/nginx-craft) advise removing the trailing slash, but since we were formerly on Wordpress and had a trailing slash to begin with, I want to be consistent with the past history in Google Analytics.
  
  **Tags:** redirect, nginx
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2018-02-15. Score: 5
  
  [Nginx-Craft](https://github.com/nystudio107/nginx-craft) has an example setup that does this:
  
  <https://github.com/nystudio107/nginx-craft/blob/master/sites-available/somedomain.com.conf#L60>
  
  ```
  # 301 Redirect URLs with trailing /'s as per https://webmasters.googleblog.com/2010/04/to-slash-or-not-to-slash.html
  rewrite ^/(.*)/$ /$1 permanent;
  
  ```
  
  This is working on the nystudio107.com site, if you go here:
  
  <https://nystudio107.com/blog/>
  
  ...the redirected URL will be this:
  
  <https://nystudio107.com/blog>
  
  Or am I missing something?
  
  ```
  andrew@kotak ~ $ curl -I https://nystudio107.com/blog/
  HTTP/1.1 301 Moved Permanently
  Server: nginx/1.13.6
  Date: Thu, 15 Feb 2018 19:39:49 GMT
  Content-Type: text/html
  Location: https://nystudio107.com/blog
  Connection: keep-alive
  Set-Cookie: abtest=green;Path=/;Max-Age=86400;secure; SameSite=strict
  Strict-Transport-Security: max-age=15768000; includeSubDomains; preload
  X-Frame-Options: SAMEORIGIN
  X-XSS-Protection: 1; mode=block
  X-Content-Type-Options: nosniff
  Referrer-Policy: no-referrer-when-downgrade
  
  ```
  
  > **Comments:**
  > **username_0**: Ah! I totally misread that in the example. I'm trying to add trailing slashes, not remove them. Fast response! I've also amended the question/answer. The one thing I still run into is query strings on slashed paths, ie domain.com/path?query=string has issues, whereas domain.com/path/?query=string is fine. Any insight?  
  > **username_0**: Nvm, figured it out!  
  > **username_1**: Only heretics add slashes. We remove them   
  
  ---
  
  ### Answer by username_0 on 2018-02-15. Score: 4
  
  After some digging, there appear to be two ways that avoid hitting the admin and url query strings.
  
  The first, (and apparently better one, as '[if is evil](https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/)' according to nginx) uses location handlers:
  
  ```
  # 301 Redirect for trailing slash
  location ~ ^([^.\?]*[^/])$ {
    try_files $uri @addslash;
  }
  
  # 301 Redirect for trailing slash
  location @addslash {
    return 301 $uri/$is_args$args;
  }
  
  # Root directory location handler
  location / {
      try_files $uri/index.html $uri $uri/ /index.php?$query_string;
  }
  
  ```
  
  The second, more evil one that uses an if statement:
  
  ```
  if ($request_uri !~ "^/admin")
  {
      rewrite ^([^.\?]*[^/])$ $1/$is_args$args permanent;
  }
  
  ```
  
  I included the context of the root location handler in the first solution so that you can combine it with your existing root location handling setup. I'm currently leaning on a lot of NYStudio's work (a truly incredible contributor to the open source ecosystem of Craft) with FastCGI, location handlers for foreign languages, etc and both of these solutions work with it.
  
  The first also works with query strings, if a user visits a URL either with or without a trailing slash. For example:
  
  * This: www.domain.com/page?string=234
  * Will go to this: www.domain.com/page/?string=234
  * And this: www.domain.com/page
  * Will go to this: www.domain.com/page/
  
  Interestingly, if you use query\_string instead of is\_args for the return url, it will rewrite it wrong. Only is\_args worked in my experience.
  
  
  ---
  
  