The code searches for TRUSTED IPs with TRUSTED ports or HOSTNAME:PORT that are set by onboard utilities through incorrect holes. You will see everything for yourselves now.
/usr/local/hestia/web-terminal/server.js (You can get it through sudo systemctl status hestia-web-terminal.service -l)
const wss = new WebSocketServer({
port: parseInt(config.WEB_TERMINAL_PORT, 10),
verifyClient: async (info, cb) => {
if (!info.req.headers.cookie.includes(sessionName)) { // Markup 1
cb(false, 401, 'Unauthorized');
return;
}
const origin = info.origin || info.req.headers.origin; // Markup 2
let matches = origin === `https://${hostname}:${config.BACKEND_PORT}`; // Markup 3
if (!matches) {
for (const ip of Object.keys(systemIPs)) {
if (origin === `https://${ip}:${config.BACKEND_PORT}`) { // Markup 4
matches = true;
break;
}
}
}
if (matches) {
cb(true);
return;
}
cb(false, 403, 'Forbidden'); // Markup 5
},
});
This is what the code that causes the connection problem looks like.
For convenience, I have marked the lines that interest us.
-
We won’t dwell on 1 for long; this is where you usually get a 401 error. If you have this error, you need to go to the forum for failed hackers.
-
is the line that your user enters in the browser hoping to reach your Gravitsapa (web panel). For example, panel.example.com.
-
Let’s look further. The script compares what the user entered with this king-of-the-hill construction := hostname (which you entered in Settings → Configure → Basic Options → Hostname) and the service port it is looking for in the hestiacp config. (Did you think you could name the machine something other than the domain name? Naive.)
Of course, in most cases it doesn’t find it (this is where all the proxy lovers drop out lol), but we move on.
-
It searches for a list of system IPs, assigns a port from the config by analogy with 3, and looks at the dropped socket with a blank stare, giving it a 403 error. IMPORTANT. This will only work normally if your server is NOT behind NAT (if we are talking about access via IP:Port). It takes the IP addresses of the machine’s network adapters.
-
Here you get your forbidden and end up in this thread.
It would seem, what could be the solution? Engineering and invention
sudo nano /usr/local/hestia/web-terminal/server.js
const wss = new WebSocketServer({
port: parseInt(config.WEB_TERMINAL_PORT, 10),
verifyClient: async (info, cb) => {
if (!info.req.headers.cookie.includes(sessionName)) {
cb(false, 401, 'Unauthorized');
return;
}
const origin = info.origin || info.req.headers.origin;
let matches = origin === `https://${hostname}:${config.BACKEND_PORT}`;
if (!matches) {
for (const ip of Object.keys(systemIPs)) {
if (origin === `https://${ip}:${config.BACKEND_PORT}`) {
matches = true;
break;
}
}
}
if (!matches && origin === `https://${config.THRUSTED_DOMAIN}`) {
matches = true;
}
if (matches) {
cb(true);
return;
}
cb(false, 403, 'Forbidden');
},
});
- Apply it
sudo systemctl restart hestia-web-terminal.service
- Make it legit
sudo nano /usr/local/hestia/bin/v-list-sys-config
Find somesing like that.
"VERSION": "'$VERSION'",
"WEBMAIL_ALIAS": "'$WEBMAIL_ALIAS'",
"WEBMAIL_SYSTEM": "'$WEBMAIL_SYSTEM'",
"WEB_BACKEND": "'$WEB_BACKEND'",
"WEB_PORT": "'$WEB_PORT'",
"WEB_RGROUPS": "'$WEB_RGROUPS'",
"WEB_SSL": "'$WEB_SSL'",
"WEB_SSL_PORT": "'$WEB_SSL_PORT'",
"WEB_SYSTEM": "'$WEB_SYSTEM'",
"WEB_TERMINAL": "'$WEB_TERMINAL'",
"WEB_TERMINAL_PORT": "'$WEB_TERMINAL_PORT'", # DONT FORGET THIS COMMA
"THRUSTED_DOMAIN" : "'$THRUSTED_DOMAIN'" #Add this string
}
}'
}
# Shell list
- Make it configurable
sudo nano /usr/local/hestia/conf/hestia.conf
WEB_SSL='openssl'
WEB_SSL_PORT='443'
WEB_SYSTEM='nginx'
WEB_TERMINAL_PORT='8085'
WEB_TERMINAL='true'
THRUSTED_DOMAIN='example.com' # Add this string and replace placeholder with your domain (add port if you not brave enought)
- At least, make it alive
sudo systemctl restart hestia
Enjoy.