Replies: 15 comments 9 replies
-
|
Hi @DRO34, thanks for the detailed report (the screenshots help a lot). Why your strict policies show a white pageThe blank page comes down to one thing: Next.js cannot hydrate.
Your third policy works because it allows everything, but it is far too loose. Below is a tight policy that allows exactly what ProxCenter loads at runtime and nothing else. Recommended policy (paste-ready)add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob: https://*.tile.openstreetmap.org https://*.basemaps.cartocdn.com https://flagcdn.com; connect-src 'self' https://nominatim.openstreetmap.org https://api.github.com; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none';" always;What each addition is for
A few important notes:
The one honest caveat
Roll it out safelyDeploy it as report-only first, so nothing breaks while you watch for violations: add_header Content-Security-Policy-Report-Only "...same value as above..." always;Then open the browser DevTools Console and exercise the consoles, the Topology and datacenter maps, and the About dialog. Any blocked resource is logged with the exact directive to adjust. Once the report-only run is clean, switch the header back to the enforcing Let me know if anything still gets blocked and paste the violation line, happy to refine. |
Beta Was this translation helpful? Give feedback.
-
|
Thank you for detailed info. One thing, i used x-frame DENY are you saying i must use sameorigin? or when you say same origin it is in a different context? im going to test this now. |
Beta Was this translation helpful? Give feedback.
-
|
That works, thank you! and i am still usign x-frame DENY. Also, the unsafe-inline is that required for the console? I know that can be a weak point. |
Beta Was this translation helpful? Give feedback.
-
|
@DRO34 Glad it works. Two good questions. X-Frame-Options: DENY vs SAMEORIGIN Keep DENY, it is the right choice. My "same origin" note referred to a different thing: where the consoles open their WebSocket (back to the same domain ProxCenter is served from), which is governed by X-Frame-Options controls who may embed ProxCenter inside an For reference, the Is Partly, but it is not specific to the console. Two things both need it:
So reworking only the console would not let you drop it, the main app would still require it. The only clean way to remove it entirely is nonce-based CSP, where the server stamps a per-request nonce that both the Next.js scripts and the console inline scripts carry. That is an app-side change, on our radar. On the weak-point concern: it is a contained one. With |
Beta Was this translation helpful? Give feedback.
-
|
Just came across this error.. I am assuming it has to do with the nginx block.. Any ideas?
|
Beta Was this translation helpful? Give feedback.
-
|
Hi @DRO34, good news: this one is not related to your CSP / nginx setup. It is the same frontend bug as #397: the backup job Run now action called an endpoint that does not exist, so the browser received the HTML error page and the JSON parser failed on Fixed in #398 (merged to |
Beta Was this translation helpful? Give feedback.
-
|
Hi @DRO34, thanks for the follow-up. Good news: this is not the same bug as before, and the difference is right there in the error text. On June 9 the error read This time it reads Why the Backups tab specifically: loading backup jobs makes several sequential Proxmox API calls inside one request (the cluster backup schedule, then storages, nodes, and per-node storage status). On a cluster with slow storage that single request can run long, and if it exceeds nginx's To confirm and fix, could you grab two things:
If it is a 504 (timeout), raising the proxy timeouts on the ProxCenter location block fixes it: proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_connect_timeout 75s;If it is a 502, the timeouts will not help, the app container itself is the thing to check (is it up, did it restart, On our side: the UI should not have shown you a raw Send me the status code and the nginx log line and I will confirm the exact tweak. |
Beta Was this translation helpful? Give feedback.
-
|
Hi @DRO34, this is the one. And it is fixable in your nginx, not in ProxCenter. Your screenshot settles it. The 403 response carries Server: nginx, Content-Type: text/html, Content-Length: 548. That is nginx's own default "403 Forbidden" page (~548 bytes, no One thing to clear up: the CSP, X-Frame-Options: DENY and HSTS headers you see on that 403 are there because they are Now, why only the Backups tab and the PBS view, while every other tab works. Those are the only two screens whose request URL contains the word "backup":
Every other tab (Summary, Nodes, Guests, HA) calls URLs with no "backup" in them, and those load fine. That pattern is the tell: somewhere in your nginx config there is a rule that denies any URL containing "backup". It is a very common anti-scanner snippet (it exists to block bots probing for /backup.zip, /backup.sql and friends), something along the lines of: location ~* backup { deny all; }
# or
if ($request_uri ~* "backup") { return 403; }It does its job against scanners, but it also catches ProxCenter's legitimate backup-jobs and pbs/.../backups API paths. To confirm in 5 seconds, grep your nginx error log while reloading the Backups tab: grep -i backup /var/log/nginx/error.log | tailA path-deny rule logs "access forbidden by rule". If instead you run ModSecurity or another WAF in front, tell me and check its audit log for the blocking rule ID, the fix is the same idea. The fix: make that backup-deny rule not apply to ProxCenter. ProxCenter serves its API under /api/, so the cleanest options are either to scope the scanner rule to a literal extension instead of the bare word (for example deny only On our side: a coming release makes the Backups tab show a clear "backend returned HTTP 403" instead of that cryptic Unexpected token message, so this kind of thing points at the real status straight away. That is cosmetic though, the nginx rule is the actual fix. Paste the matching error.log line and I will give you the exact edit. |
Beta Was this translation helpful? Give feedback.
-
|
Hi @DRO34, the empty An nginx Three quick things, the first is the most decisive: 1. curl the failing URL directly, plus a working one for contrast. In DevTools Network, copy the exact failing request URL (the one to # the failing one
curl -sk -i 'https://YOUR-HOST/api/v1/pbs/REPLACE-ID/backups'
# a working one, for contrast
curl -sk -i 'https://YOUR-HOST/api/v1/connections'If the first returns that little HTML 403 page while the second returns JSON, that confirms the block happens at the proxy/WAF on the URL itself, before the request ever reaches ProxCenter (ProxCenter only ever answers JSON, even on errors). The footer of the HTML page usually names what produced it (nginx, or CrowdSec), which tells us where to aim. 2. Search the fully merged nginx config for a silent 403 rule: sudo nginx -T 2>&1 | grep -niE 'return 403|deny|location ~|map |backup|modsec|naxsi|appsec|lua'
3. Check CrowdSec's AppSec layer specifically. A normal IP ban would block all your traffic, not only the backup URLs, so that's not it. But the AppSec/WAF component inspects the URL and can 403 specific paths, and its rules do block paths containing "backup": sudo cscli decisions list
sudo cscli appsec-configs list
sudo cscli appsec-rules list
sudo cscli alerts listIf Paste back the curl output and whichever of those shows a hit, and I'll give you the exact one-line edit. On our side, a coming release makes the Backups tab show a clear "backend returned HTTP 403" instead of the cryptic |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
|
Hi @DRO34, your internal test was a good idea, but the response headers settle this, and not where the test assumed. Look at your two curls. The working So nginx answers it and ProxCenter is cleared. What is left is which thing behind nginx decides the 403. Two candidates, and the headers cannot separate them:
Your empty Three commands name the culprit: # 1. Real bypass: hit the container directly, skipping nginx, from the Docker host
curl -ski http://127.0.0.1:<proxcenter-port>/api/v1/pbs/<id>/backups
# JSON back (a 401 is fine) = ProxCenter cleared, block is at the proxy
# 2. Plain nginx rule? Merged config, includes resolved
sudo nginx -T 2>&1 | grep -niE 'return 403|deny|location ~|backup'
# 3. AppSec? Reload the Backups tab, then
sudo cscli alerts list # or live: sudo journalctl -u crowdsec -fWhichever returns a hit is the source, and the fix follows: an AppSec exemption for On our side, a coming release shows "backend returned HTTP 403" instead of the cryptic |
Beta Was this translation helpful? Give feedback.
-
|
Your 403 comes from nginx (it says If you want to see that with your own eyes, one command from the Docker host (note the quotes, and the id can be anything): curl -ski 'http://127.0.0.1:3000/api/v1/pbs/x/backups'JSON back (even a 401 or 404) confirms ProxCenter answers fine and the block is purely in front of it. The fix is on the proxy side: allow ProxCenter's On our side, a coming release shows "backend returned HTTP 403" instead of the cryptic |
Beta Was this translation helpful? Give feedback.
-
|
That's the one. The bare The cleanest fix keeps the rule intact for everything else and just exempts ProxCenter's API. ProxCenter serves all its calls under location ~* "^(?!/api/).*/(wp-admin|wp-login|xmlrpc|phpmyadmin|pma|adminer|admin/config|\.env|\.git|\.svn|backup|\.bak|web\.config|composer\.json|package\.json)" {
deny all;
access_log off;
log_not_found off;
}That still blocks sudo nginx -t && sudo systemctl reload nginxIf you would rather not edit the regex, the alternative is a higher-priority Reload, reopen the Backups tab and the PBS view, and both should load. This is purely a proxy change, nothing in ProxCenter. |
Beta Was this translation helpful? Give feedback.
-
|
This change fixed it here, still maintains actual backup-file scans.. Now i can see the backups location ~* "/(wp-admin|wp-login|xmlrpc|phpmyadmin|pma|adminer|admin/config|.env|.git|.svn|.bak|web.config|composer.json|package.json)" { location ~* "^/(backup|backups)/" { |
Beta Was this translation helpful? Give feedback.
-
|
Perfect ! We can closed the issue ? |
Beta Was this translation helpful? Give feedback.






Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello, can you please tell me the proper policy syntax for the content security policy in nginx? the CSP..
I am not sure what proxcenter requires to fully load
I have tried these both so far. They both produce white pages dont fully load content.
"default-src 'self'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none';" always;
"default-src 'self'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self';" always;
This works but obviously way less secure
"default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: wss: https:;" always;
Can you please confirm best policy to get full functionality but also the most secure? Thanks
Here is an example of the white page.
With CSP line commented out, page loads fine or the basic line presented above it works.
Beta Was this translation helpful? Give feedback.
All reactions