How do I delete the file of user avatar?

To prevent users from uploading future avatars, you can disable allow uploaded avatars and enable the selectable avatars site setting with a large selection.

I think you may need to upload a replacement placeholder in order for automatic deletion - the user record is still keeping the uploaded avatar image alive even though it’s not in use.

Upload files are named based on the SHA1 of the image content - that may help you to find the backing file?


Something like

a=UserAvatar.where(user_id: 1234)


cd /var/discourse/shared/standalone

I have over 7k registered users and only less than 5 users use illegal avatars w/o knowing it, so I don’t want to make it a 0 or 1 problem; I want to solve it case by case rather than stopping all users from using custom avatars.

How do I do this? I have no idea at all


For example this image

snakeninny@bogon ~ % shasum /Users/snakeninny/Desktop/5414_2.png.jpeg 
c8d561c5484a1f197abd32995411caaa25e53bd6  /Users/snakeninny/Desktop/5414_2.png.jpeg
root@iosre:~# cd /var/discourse/shared/standalone
root@iosre:/var/discourse/shared/standalone# find ./ -name *c8d561c5484a1f197abd32995411caaa25e53bd6*

No luck. Is this what you mean? And any ideas?

1 Like

Is this a piece of code? Where and how do I execute it? I used to be an iOS developer and am not familiar with front-end programming

1 Like

It’s for the rails console. You’d get there with

cd /var/discourse 
./launcher enter app 
rails c

You can use exit to quit. And inside the container you cd to /shared rather than the full path above.


For user lincwee in
UserAvatar.where(user_id: 'lincwee') returns an empty array. Any ideas?

root@iosre:~# cd /var/discourse/shared/
root@iosre:/var/discourse/shared# /var/discourse/launcher enter app 
WARNING: Docker version 17.05.0-ce deprecated, recommend upgrade to 17.06.2 or newer.
root@iosre-app:/var/www/discourse# rails c
[1] pry(main)> a=UserAvatar.where(user_id: 1234)
=> []
[2] pry(main)> a=UserAvatar.where(user_id: lincwee)
NameError: undefined local variable or method `lincwee' for main:Object
from (pry):2:in `__pry__'
[3] pry(main)> a=UserAvatar.where(user_id: 'lincwee')
=> []
[4] pry(main)> 
1 Like

You’ll need the ID, not username.

u=User.find_by(username: "lincwee")

You can then see the id or access it with


Thanks it worked to some extent. I’ve run

cd /var/discourse/shared/
/var/discourse/launcher enter app
rails c

In the terminal and then executed the code

uid = User.find_by(username: "user_name").id
user_avatars = UserAvatar.where(user_id: uid)
user_avatar = user_avatars[0]
upload_url = Upload.find(user_avatar.custom_upload_id).url

to list all avatar URLs and deleted them from my server.
But I guess I still need to further refresh the system/cache? How should I do this?


I got another email from my CDN provider and they have frozen my CDN account. So I have to update this thread for further help.

The new email said that the following links were illegal.

As you can see these are 2 user avatars, which are memes of a former Chinese president. Again, the CDN provider asked me to delete these files on the server and refresh CDN.

I could see from the link that the users were “baal998” and “lincwee”. According to the code snippet in my last post, the uploaded avatar URL of “lincwee” was /uploads/default/original/2X/5/55512211b1c8969c8038b79840464952cd3eb089.jpeg while for “baal998” it was /uploads/default/original/2X/c/cb2188eaeecc3a648f021fa00da4734bd60ca183.jpg. I then run find /var/discourse/shared/ -name *55512211b1c8969c8038b79840464952cd3eb089* and deleted all files found, it worked for “lincwee”. But no luck on “baal998”, I could still access even though there were no more files with the name *cb2188eaeecc3a648f021fa00da4734bd60ca183*.

So where the hell is stored on my server? :sob:

1 Like

Hmm, that is a difficult situation. Maybe @falco or someone else who worked on avatars recently could advise you?


Or to make it simpler: How does Discourse parse a visit to If someone familiar with the source code can tell me the source file or the class/function, that would be really helpful. Thanks!

1 Like

Look in the Uploads model, I think.

Also, start with pulling from your server, not the CDN. You want to be sure that you are solving the problem in the right place. Once you’re sure that the server isn’t sending the images you can work with the CDN.

1 Like

Since is from CDN, is supposed to be from my server, right?


Yes and you see that it is getting sent by your server. So that’s the link to be trying to fix. After you make that stop sending the images you can clear the CDN


This is the goal that I have no idea how to achieve. As an iOS reverse engineer, my idea is that if I know in the source code how/where the server sends this image, I can track back and see where the server loads this image locally. But I read Ruby like reading seudo code, so locating where the server sends this image becomes a great great task for me :sob: That should be a lot easier for a person who’re familiar with the source code though

1 Like

In discourse/upload.rb at master · discourse/discourse · GitHub

I saw the table uploads which stored all the uploads of a user. For user Baal998 whose user ID is 1637, I then run SELECT * FROM uploads WHERE user_id = '1637'; and the result is

  id  | user_id | original_filename | filesize | width | height |                                     url                                     |         created_at         |         updated_at         |                   sha1                   | origin | retain_hours | extension | thumbnail_width | thumbnail_height | etag | secure | access_control_post_id | original_sha1 | animated | verified | verification_status 
 2210 |    1637 | 2.pic.jpg         |    60610 |       |        | /uploads/default/original/2X/c/cb2188eaeecc3a648f021fa00da4734bd60ca183.jpg | 2016-08-08 09:37:13.937306 | 2018-01-05 02:38:49.498264 | cb2188eaeecc3a648f021fa00da4734bd60ca183 |        |              | jpg       |                 |                  |      | f      |                        |               |          |          |                   1
(1 row)

Which is the same to running Upload.find(user_avatar.custom_upload_id).url with rails.

My guess is that after the user uploaded avatar, discourse will do something to the original avatar file and store the optimized files in somewhere else?

1 Like

In table optimized_images this row seemed suspicious

  id   |                   sha1                   | extension | width | height | upload_id |                                          url                                           | filesize | etag | version |         created_at         |         updated_at         
 49538 | e6dc9b0d6c18f2a4c3c0d2027534d01cfc89c84e | .jpg      |   135 |    135 |      2210 | /uploads/default/optimized/2X/c/cb2188eaeecc3a648f021fa00da4734bd60ca183_2_135x135.jpg |    10968 |      |       2 | 2016-08-08 09:37:13.937306 | 2016-08-08 09:37:13.937306
(1 row)

The sha1 and filesize matches , but on server this file doesn’t exist.

root@iosre:/var/discourse/shared/standalone# ls /uploads/default/optimized/2X/c/cb2188eaeecc3a648f021fa00da4734bd60ca183_2_135x135.jpg
ls: cannot access /uploads/default/optimized/2X/c/cb2188eaeecc3a648f021fa00da4734bd60ca183_2_135x135.jpg: No such file or directory

No idea what was wrong.

Problem solved:

Someone from my forum told me that this avatar image might be stored in nginx cache under proxy_cache_path, which was usually /var/nginx/cache, but I couldn’t find either proxy_cache_path or /var/nginx/cache.

I was inspired by him that I entered the discourse app via launcher enter app and then found nginx cache:

root@iosre:/var/discourse/shared# /var/discourse/launcher enter app
WARNING: Docker version 17.05.0-ce deprecated, recommend upgrade to 17.06.2 or newer.
root@iosre-app:/var/www/discourse# cd /var/nginx/cache
root@iosre-app:/var/nginx/cache# ls
0  1  2  3  4  5  6  7	8  9  a  b  c  d  e  f

And deleted all the caches:

root@iosre-app:/var/nginx/cache# ls

The image was gone.


This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.