<p>It appears nginx is setup correctly. In Craft, your Assets URL can be different than your assets path, which I think is where some confusion is coming in.</p>

<p>If Craft's file upload path is outside nginx <code>root</code> (otherwise known as the <code>DocumentRoot</code> directive in Apache), you could either move your asset storage so it's <em>under</em> the document root—and thus "public" or "virtually move" the <code>root</code> folder so nginx will serve from that directory instead of the actual "images" folder.</p>

<pre><code>location /images/ {
  /root /srv/craft/uploads
}
</code></pre>

<p>As with great power comes great responsibility. If you use the virtual rewriting option, be careful to always specify a default document root, and only override the root inside a location unless you have to <a href="https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#root-inside-location-block" rel="nofollow">as noted in nginx docs</a>, or nothing will match and you'll pull your hair out as to why nothing matches.</p>

CC BY-SA 3.0
2016-01-15T13:08:01.427Z
OK I've updated my Nginx configuration with the advice you have provided, and it works. Thanks again.
sctgraham
CC BY-SA 3.0
2016-01-14T23:42:59.710Z
2016-01-14T23:42:59.710Z
RitterKnight
<p>Just had a similar issue with a colleague. <strong>Double check your folder permissions</strong>. It might be the case that Craft isn’t allowed to write the transformed files to your assets folder.</p>

<p>Something like <code>chmod -R 777 public/assets</code> might do the trick. </p>

<p>(You might want set this to something other than <code>777</code> if it worked out. Look at <a href="https://craftcms.com/docs/installing#step-2-set-the-permissions" rel="nofollow noreferrer">the docs</a> for details.)</p>

CC BY-SA 4.0
2020-02-06T23:19:49.473Z
Thank you for this! I needed to change my upload directory to use 777 permissions to get things working.
Anna_MediaGirl
CC BY-SA 3.0
2017-07-18T14:52:19.180Z
2017-07-18T14:52:19.180Z
medoingthings
<p>Not a direct answer to your question, but I keep a pretty up to date Nginx config for Craft here: <a href="https://github.com/nystudio107/nginx-craft" rel="nofollow noreferrer">Nginx-Craft</a> that may be useful to you at some point.</p>

<p>Glad you got it sorted.</p>

CC BY-SA 3.0
2017-07-18T16:12:36.657Z
2017-07-18T16:12:36.657Z
andrew.welch
<p>I replaced some of my Nginx configuration with the ones from here:</p>
<p>[https://github.com/nystudio107/nginx-craft/blob/master/sites-available/basic_localdev.com.conf][1]</p>
<p>I believe this line is what resolved it for me</p>
<p>location / {
try_files $uri/index.html $uri $uri/ /index.php?$query_string;
}</p>

CC BY-SA 4.0
2021-03-26T12:47:54.350Z
2021-03-26T12:47:54.350Z
Victor Ighalo
<p>I have the following issue which I can't seem to wrap my head around. </p>

<p>All images assets uploaded to Craft return a 404 not found on the front-end. Everything works fine in the admin CP though (uploading, renaming, thumbnails, etc.). Any template with <code>getUrl()</code> outputs the correct URL but the resource returns a 404 status code. When I navigate directly to the asset's URL, Craft returns a 404 template instead of the image. </p>

<p>These are the things I have checked so far :</p>

<ul>
<li>Files permissions seem OK (775 on folder and 664 on files) on the "craft" user;</li>
<li>The assets paths is <code>{basePath}uploads/images/</code></li>
<li>The assets URL is <code>{siteUrl}images/</code></li>
<li>Both <code>{basePath}</code> and <code>{siteUrl}</code> are correctly set as environment variables in <code>general.php</code></li>
<li>I'm running Nginx with a config similar to <a href="https://craftcms.stackexchange.com/a/8971">this answer</a></li>
</ul>

<p>Any thoughts ? This is really bugging me.</p>

<p>Thanks.</p>

<p><strong>Edit</strong></p>

<p>These are my two nginx configuration files :</p>

<pre><code># nginx.conf

user craft craft;
worker_processes auto;
worker_rlimit_nofile 8192;
events {
    worker_connections 8000;
}

error_log /var/log/nginx/error.log debug; # not for production
pid /var/run/nginx.pid;


http {

    disable_symlinks off;
    proxy_buffering on;
    proxy_buffer_size 8k;
    proxy_buffers 2048 8k;
    proxy_connect_timeout  600s;
    proxy_send_timeout  600s;
    proxy_read_timeout  600s;
    fastcgi_send_timeout 600s;
    fastcgi_read_timeout 600s;

    rewrite_log on;
    access_log /var/log/nginx/access.log;

    server_tokens off;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    keepalive_timeout   65;
    sendfile            on;
    tcp_nopush          on;
    gzip                on;
    gzip_comp_level     5;
    gzip_min_length     256;
    gzip_proxied        any;
    gzip_vary           on;
    gzip_disable        "msie6";

    include /etc/nginx/sites-enabled/*;
}
</code></pre>

<p>and </p>

<pre><code># site.conf

# -------------------------------------------------
# General server configuration

server {

  listen 80 default_server;
  server_name example.com;
  root /srv/craft/public;
  index index.php index.html index.htm;
  charset utf-8;
  error_page 404 /index.php;
  error_log /var/log/nginx/example.com.error.log debug;
  access_log /var/log/nginx/example.com.access.log;

  # -------------------------------------------------
  # Some locations to help during dev, remove for production

  location = /phpinfo {
    try_files $uri $uri/ /phpinfo.php$is_args$args;
  }

  location = /status {
     access_log off;
     allow all;
     include fastcgi_params;
     fastcgi_param SCRIPT_FILENAME /status;
     fastcgi_pass unix:/var/run/php-fpm.sock;
  }

  location = /ping {
     access_log off;
     allow all;
     include fastcgi_params;
     fastcgi_param SCRIPT_FILENAME /ping;
     fastcgi_pass unix:/var/run/php-fpm.sock;
  }

  # -------------------------------------------------
  # Static assets (css, js, fonts, etc.) location

  location /src {
      root /srv/craft/public/src;
      expires 1y;
      access_log off;
      add_header Pragma public;
      add_header Cache-Control "public";
  }

  # -------------------------------------------------
  # Craft application locations

  location / {
    try_files $uri $uri/ @rewrites;
  }

  location @rewrites {
    rewrite ^(.*) /index.php?p=$1 last;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }

  # cache.appcache, your document html and data
  location ~* \.(?:manifest|appcache|html?|xml|json)$ {
      try_files $uri /index.php?$query_string;
      expires -1;
  }

  # Feed
  location ~* \.(?:rss|atom)$ {
      try_files $uri /index.php?$query_string;
      expires 1h;
      add_header Cache-Control "public";
  }

  # Media: images, icons, video, audio, HTC
  location ~* \.(?:jpg|jpeg|gif|png|pdf|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
      try_files $uri /index.php?$query_string;
      expires 1M;
      add_header Pragma public;
      add_header Cache-Control "public";
  }

  # CSS and Javascript
  location ~* \.(?:css|js)$ {
      try_files $uri /index.php?$query_string;
      expires 1y;
      add_header Pragma public;
      add_header Cache-Control "public";
  }

  # -------------------------------------------------
  # Other static ressources

  # Favicons
  location = /favicon.ico {
      access_log off;
      log_not_found off;
  }

  # Robots.txt
  location = /robots.txt {
      access_log off;
      log_not_found off;
  }

  # Humans.txt
  location = /humans.txt {
      access_log off;
      log_not_found off;
  }

  # Prevent clients from accessing hidden files (starting with a dot)
  # This is particularly important if you store .htpasswd files in the site hierarchy
  location ~* (?:^|/)\. {
      deny all;
  }
  # Prevent clients from accessing to backup/config/source files
  location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
      deny all;
  }

}
</code></pre>

CC BY-SA 3.0
2016-01-14T18:10:10.620Z
Can you post your nginx config?  It sounds like one of the rules dealing with static files isn't being followed. That could be for number of reasons. As a general rule, when processing a config, nginx looks for more exact rules first and then down to less and less specific.
RitterKnight
CC BY-SA 3.0
2016-01-14T19:00:53.103Z
Shouldn't the assets URL be `{siteUrl}uploads/images`?
megatrond
CC BY-SA 3.0
2016-01-14T21:38:55.090Z
@RitterKnight I've added the Nginx files, you'll see a /src location which is working fine to serve static ressources (JS, CSS, fonts and UI images) not managed by craft. Maybe something is wrong with the media location further down the file.
sctgraham
CC BY-SA 3.0
2016-01-14T21:43:06.590Z
@megatrond No, I want the images to be served from example.com/images/ but I don't think the folder path should necessarily match that url fragment for this to work. At least I hope not !
sctgraham
CC BY-SA 3.0
2016-01-14T21:56:19.087Z
It appears like nginx is setup correctly what what I can tell. I would double check your asset source's location.  Where are the images that craft maintains stored? I would guess under /images/? Those have to be some folder under /public as well unless you have a nginx rule that rewrites them.
RitterKnight
CC BY-SA 3.0
2016-01-14T22:15:14.430Z
Just rereading your question, your Assets URL should match your assets path. If i'm reading your config right, BasePath would be ``/srv/craft/public``.  I would guess your URLs are coming out like ``whatever.com/images/`` when they should be coming out like ``whatever.com/uploads/images``.
RitterKnight
CC BY-SA 3.0
2016-01-14T22:16:30.653Z
@RitterKnight you are right, my folder location is outside the Nginx root path. It's actually under /srv/craft/uploads/ and not /srv/craft/public. I wanted to keep those files separate for version control reasons. So that's more than likely the issue, I'm off to test this now. However, one quick question  : would the solution be as simple as adding "root /srv/craft/uploads/" to the media location or will this potentially interfere with any other Craft media files ? Thanks a mil for you time and help.
sctgraham
CC BY-SA 3.0
2016-01-14T22:33:28.580Z
Craft's static assets from the CP get served by PHP so you should be good there. Yeh if you make  new ``location /images`` block, the root you mention would serve it out of that directory and nginx would use files in that location when it encounters something from ``whatever.com/images/``.
RitterKnight
<assets><image><404><debugging>
Assets (images) return a 404 on the front-end
# Assets (images) return a 404 on the front-end

(Asked by: username_0 on 2016-01-14)

I have the following issue which I can't seem to wrap my head around. 
All images assets uploaded to Craft return a 404 not found on the front-end. Everything works fine in the admin CP though (uploading, renaming, thumbnails, etc.). Any template with getUrl() outputs the correct URL but the resource returns a 404 status code. When I navigate directly to the asset's URL, Craft returns a 404 template instead of the image. 
These are the things I have checked so far :

Files permissions seem OK (775 on folder and 664 on files) on the "craft" user;
The assets paths is {basePath}uploads/images/
The assets URL is {siteUrl}images/
Both {basePath} and {siteUrl} are correctly set as environment variables in general.php
I'm running Nginx with a config similar to this answer

Any thoughts ? This is really bugging me.
Thanks.
Edit
These are my two nginx configuration files :
# nginx.conf

user craft craft;
worker_processes auto;
worker_rlimit_nofile 8192;
events {
    worker_connections 8000;
}

error_log /var/log/nginx/error.log debug; # not for production
pid /var/run/nginx.pid;


http {

    disable_symlinks off;
    proxy_buffering on;
    proxy_buffer_size 8k;
    proxy_buffers 2048 8k;
    proxy_connect_timeout  600s;
    proxy_send_timeout  600s;
    proxy_read_timeout  600s;
    fastcgi_send_timeout 600s;
    fastcgi_read_timeout 600s;

    rewrite_log on;
    access_log /var/log/nginx/access.log;

    server_tokens off;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    keepalive_timeout   65;
    sendfile            on;
    tcp_nopush          on;
    gzip                on;
    gzip_comp_level     5;
    gzip_min_length     256;
    gzip_proxied        any;
    gzip_vary           on;
    gzip_disable        "msie6";

    include /etc/nginx/sites-enabled/*;
}

and 
# site.conf

# -------------------------------------------------
# General server configuration

server {

  listen 80 default_server;
  server_name example.com;
  root /srv/craft/public;
  index index.php index.html index.htm;
  charset utf-8;
  error_page 404 /index.php;
  error_log /var/log/nginx/example.com.error.log debug;
  access_log /var/log/nginx/example.com.access.log;

  # -------------------------------------------------
  # Some locations to help during dev, remove for production

  location = /phpinfo {
    try_files $uri $uri/ /phpinfo.php$is_args$args;
  }

  location = /status {
     access_log off;
     allow all;
     include fastcgi_params;
     fastcgi_param SCRIPT_FILENAME /status;
     fastcgi_pass unix:/var/run/php-fpm.sock;
  }

  location = /ping {
     access_log off;
     allow all;
     include fastcgi_params;
     fastcgi_param SCRIPT_FILENAME /ping;
     fastcgi_pass unix:/var/run/php-fpm.sock;
  }

  # -------------------------------------------------
  # Static assets (css, js, fonts, etc.) location

  location /src {
      root /srv/craft/public/src;
      expires 1y;
      access_log off;
      add_header Pragma public;
      add_header Cache-Control "public";
  }

  # -------------------------------------------------
  # Craft application locations

  location / {
    try_files $uri $uri/ @rewrites;
  }

  location @rewrites {
    rewrite ^(.*) /index.php?p=$1 last;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }

  # cache.appcache, your document html and data
  location ~* \.(?:manifest|appcache|html?|xml|json)$ {
      try_files $uri /index.php?$query_string;
      expires -1;
  }

  # Feed
  location ~* \.(?:rss|atom)$ {
      try_files $uri /index.php?$query_string;
      expires 1h;
      add_header Cache-Control "public";
  }

  # Media: images, icons, video, audio, HTC
  location ~* \.(?:jpg|jpeg|gif|png|pdf|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
      try_files $uri /index.php?$query_string;
      expires 1M;
      add_header Pragma public;
      add_header Cache-Control "public";
  }

  # CSS and Javascript
  location ~* \.(?:css|js)$ {
      try_files $uri /index.php?$query_string;
      expires 1y;
      add_header Pragma public;
      add_header Cache-Control "public";
  }

  # -------------------------------------------------
  # Other static ressources

  # Favicons
  location = /favicon.ico {
      access_log off;
      log_not_found off;
  }

  # Robots.txt
  location = /robots.txt {
      access_log off;
      log_not_found off;
  }

  # Humans.txt
  location = /humans.txt {
      access_log off;
      log_not_found off;
  }

  # Prevent clients from accessing hidden files (starting with a dot)
  # This is particularly important if you store .htpasswd files in the site hierarchy
  location ~* (?:^|/)\. {
      deny all;
  }
  # Prevent clients from accessing to backup/config/source files
  location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
      deny all;
  }

}

**Tags:** assets, image, 404, debugging

> **Comments:**
> **username_1**: Can you post your nginx config?  It sounds like one of the rules dealing with static files isn't being followed. That could be for number of reasons. As a general rule, when processing a config, nginx looks for more exact rules first and then down to less and less specific.  
> **username_2**: Shouldn't the assets URL be `{siteUrl}uploads/images`?  
> **username_0**: @username_1 I've added the Nginx files, you'll see a /src location which is working fine to serve static ressources (JS, CSS, fonts and UI images) not managed by craft. Maybe something is wrong with the media location further down the file.  
> **username_0**: @username_2 No, I want the images to be served from example.com/images/ but I don't think the folder path should necessarily match that url fragment for this to work. At least I hope not !  
> **username_1**: It appears like nginx is setup correctly what what I can tell. I would double check your asset source's location.  Where are the images that craft maintains stored? I would guess under /images/? Those have to be some folder under /public as well unless you have a nginx rule that rewrites them.  
> **username_1**: Just rereading your question, your Assets URL should match your assets path. If i'm reading your config right, BasePath would be ``/srv/craft/public``.  I would guess your URLs are coming out like ``whatever.com/images/`` when they should be coming out like ``whatever.com/uploads/images``.  
> **username_0**: @username_1 you are right, my folder location is outside the Nginx root path. It's actually under /srv/craft/uploads/ and not /srv/craft/public. I wanted to keep those files separate for version control reasons. So that's more than likely the issue, I'm off to test this now. However, one quick question  : would the solution be as simple as adding "root /srv/craft/uploads/" to the media location or will this potentially interfere with any other Craft media files ? Thanks a mil for you time and help.  
> **username_1**: Craft's static assets from the CP get served by PHP so you should be good there. Yeh if you make  new ``location /images`` block, the root you mention would serve it out of that directory and nginx would use files in that location when it encounters something from ``whatever.com/images/``.  

---

## 4 answers

### Answer by username_1 on 2016-01-14. Score: 1 | Accepted answer

It appears nginx is setup correctly. In Craft, your Assets URL can be different than your assets path, which I think is where some confusion is coming in.
If Craft's file upload path is outside nginx root (otherwise known as the DocumentRoot directive in Apache), you could either move your asset storage so it's under the document root—and thus "public" or "virtually move" the root folder so nginx will serve from that directory instead of the actual "images" folder.
location /images/ {
  /root /srv/craft/uploads
}

As with great power comes great responsibility. If you use the virtual rewriting option, be careful to always specify a default document root, and only override the root inside a location unless you have to as noted in nginx docs, or nothing will match and you'll pull your hair out as to why nothing matches.

> **Comments:**
> **username_0**: OK I've updated my Nginx configuration with the advice you have provided, and it works. Thanks again.  

---

### Answer by username_3 on 2017-07-18. Score: 3

Just had a similar issue with a colleague. **Double check your folder permissions**. It might be the case that Craft isn’t allowed to write the transformed files to your assets folder.

Something like `chmod -R 777 public/assets` might do the trick.

(You might want set this to something other than `777` if it worked out. Look at [the docs](https://craftcms.com/docs/installing#step-2-set-the-permissions) for details.)

> **Comments:**
> **username_4**: Thank you for this! I needed to change my upload directory to use 777 permissions to get things working.  

---

### Answer by username_5 on 2017-07-18. Score: 1

Not a direct answer to your question, but I keep a pretty up to date Nginx config for Craft here: [Nginx-Craft](https://github.com/nystudio107/nginx-craft) that may be useful to you at some point.

Glad you got it sorted.


---

### Answer by username_6 on 2021-03-26. Score: 0

I replaced some of my Nginx configuration with the ones from here:

[https://github.com/nystudio107/nginx-craft/blob/master/sites-available/basic\_localdev.com.conf][1]

I believe this line is what resolved it for me

location / {
try\_files $uri/index.html $uri $uri/ /index.php?$query\_string;
}


---

