I’ve been using Ghost for probably 10+ years. I’m a software developer and linux admin. I don’t know everything, but this isn’t my first time setting up ghost, and my current blog has been running for a while. Newsletter emails (which I now understand to be separate from transactional emails) worked as I’ve posted a blog posted and received the corresponding email for it. Transactional emails seemed to not work in that I couldn’t register as a new user for my website.
Since updating recently from 5.x to 6.1 (and now 6.2 as of today), I notice that when I navigate to my ghost login page, there’s an error in the browser console logs immediately:
vendor-aed0068cf9b67…3a6343545b7b.js:492
GET https://website.com/blog/ghost/api/admin/users/me/?include=roles 403 (Forbidden)
This seems to correspond with the error I see in the ghost logs (ghost log -n 50):
[2025-10-05 14:22:00] ERROR “GET /blog/ghost/api/admin/users/me/?include=roles” 403 4ms
NAME: NoPermissionError
MESSAGE: Authorization failedlevel: normal
“Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication.”
NoPermissionError: Authorization failed
at authorizeAdminApi (/var/www/website.com/blog/versions/6.2.0/core/server/services/auth/authorize.js:33:25)
at Layer.handle [as handle_request] (/var/www/website.com/blog/versions/6.2.0/node_modules/express/lib/router/layer.js:95:5)
at next (/var/www/website.com/blog/versions/6.2.0/node_modules/express/lib/router/route.js:149:13)
at authenticate (/var/www/website.com/blog/versions/6.2.0/core/server/services/auth/session/middleware.js:55:13)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
That seems odd, since I haven’t even logged in yet (why would it request an object that requires authorization prior to authorization?). No matter, I continue with logging in anyways. After entering my login info and clicking “Login”, the page thinks for a good long while and eventually returns the ‘Server was unreachable’ error in the browser console logs:
ghost-2066304fd0b166…97dd73ef7b2.js:2893 O: Server was unreachable
at p.handleResponse (ghost-2066304fd0b166…d73ef7b2.js:3957:48)
at Object.<anonymous> (vendor-aed0068cf9b67…43545b7b.js:6746:70)
at l (vendor-aed0068cf9b67…43545b7b.js:201:118)
at Object.fireWith [as rejectWith] (vendor-aed0068cf9b67…43545b7b.js:202:694)
at M (vendor-aed0068cf9b67…43545b7b.js:480:468)
at XMLHttpRequest.<anonymous> (vendor-aed0068cf9b67…43545b7b.js:491:181)
vendor-aed0068cf9b67…3a6343545b7b.js:492
POST https://website.com/blog/ghost/api/admin/session net::ERR_CONNECTION_CLOSED
The following are my NGINX error logs (there are about 25 lines, they all have this same text (“upstream timed out (110: Unknown error) while reading response header from upstream”). Here is the latest entry:
2025/10/05 13:58:38 [error] 328742#328742: *83622 upstream timed out (110: Unknown error) while reading response header from upstream, client: 27.13.129.212, server: website.com, request: "POST /blog/ghost/api/admin/session HTTP/2.0", upstream: "http://127.0.0.1:2368/blog/ghost/api/admin/session", host: "website.com"
I’m just using regular Chrome browser, latest version. Tried Incognito mode (no extensions), same error. Tried with Firefox, same issue.
I found similar a similar issue reported here but it’s not clear whether it’s relevant to me. My NGINX is setup such that it redirects non-https traffic to with a return 301 to the https page instead. Here’s the section of my NGINX config relevant to ghost:
# ghost blog
location ^~ /blog {
client_max_body_size 100m;
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 24k;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:2368;
}
Does anyone see anything therein that might cause issues, or just in general know how to resolve the error I’m experiencing?
Thanks!
Update a few hours later: I’ve spent another 2+ hours debugging this issue, and it’s clear that Ghost is happily serving everything else under /blog/ghost/…
Only the session-based admin request (/users/me/?include=roles) gets a 403.
The cookie looks correct and is being set. In fact, I explicitly forward the Cookie: header (proxy_set_header Cookie $http_cookie;). I commented out all my ‘common security configurations’ in NGINX in case they were the culprit, but the issue persists.
I thought it might be my Cloudflare proxy, so I disable it entirely but I get the same issue, except the one difference being that the login page doesn’t hang forever, instead there’s a banner at the top that says “There was a problem on the server” and the login button turns red and says “Retry”. When I check the logs, it’s the same error shown as above, however.
Update a few more hours later: Updated the description of the issue.
Update after it suddenly started working: I’m still not entirely sure what actually fixed the issue but I will provide everything I changed in case it helps a future person with this issue. If I had to guess, it was that transactional emails weren’t getting through properly. I had transactional emails setup correctly in my ghost config, using the following format:
"mail": {
"from": "'HappyTHoughts' <no-reply@happythoughts.com>",
"transport": "SMTP",
"options": {
"service": "Mailgun",
"host": "smtp.mailgun.org",
"port": 465,
"secure": true,
"auth": {
"user": "mail@mg.happythoughts.com",
"pass": "<redacted>"
}
}
},
However, for some reason they weren’t working in that I couldn’t subscribe as a new user. I thought it might be my VPS firewall, so I opened up ports 465 and 587 (TCP) on the firewall. At the same time, I thought there might be an issue with the secure mode so I went from using
port: 465 and secure: true, to port: 587 and secure: false in my ghost config.
After restarting ghost this worked. It might have been the firewall though and not specifically reverting to port: 587 and secure: false. Also, Cloudflare may have been an issue as well but I can’t confirm. Maybe at some point if I get some time I will try to return to port 465 and using Cloudflare to see if it still works, and then I’ll update this post.