Nginx websockets + SSL not working (net::ERR_CERT_COMMON_NAME_INVALID) - nginx

I have a problem with running a websocket server on Nginx. This is my Nginx default.conf:
upstream websocket {
server xx.xx.xx.xx:8080;
}
server {
listen 80;
listen [::]:80;
server_name domain.com *.domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl on;
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
root /var/www/html;
index index.php index.html index.htm index.nginx-debian.html;
server_name domain.com *.domain.com;
location / {
try_files $uri $uri/ =404;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
location ~ /\.ht {
deny all;
}
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
I get the following error in chrome:
(index):2 WebSocket connection to 'wss://xx.xx.xx.xx/ws:8080' failed: Error in connection establishment: net::ERR_CERT_COMMON_NAME_INVALID
I think it has something to do with certificates (SSL) but I really have no idea to fix this!
Thanks in advance!
Edit:
My index.php file is
<script>
var conn = new WebSocket('wss://xx.xx.xx.xx/ws');
conn.onopen = function(e) {
console.log("Connection established!");
};
</script>
When I change xx.xx.xx.xx to domain.com I get a handshake error code 504.
Btw I'm running a websocket server via php (php server.php) with ratchet following this example: http://socketo.me/docs/hello-world

Configure SSL for upstream - Nginx
Prerequisites
NGINX Plus R6 and later or the latest NGINX Open Source compiled with the --with-stream and with-stream_ssl_module configuration parameters
A proxied TCP server or an upstream group of TCP servers
SSL certificates and a private key
Sample configuration:
stream {
upstream websocket {
server backend1.example.com:8080;
}
server {
listen 8080 ssl;
proxy_pass websocket;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/certs/server.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 4h;
ssl_handshake_timeout 30s;
…
}
}
For more detail please follow this link https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-tcp/

No mention of the port in your supplied code, but you are attempting to make a secure websocket connection directly from the browser to your websocket server, which is running on port 8080. Hence this message:
(index):2 WebSocket connection to 'wss://xx.xx.xx.xx/ws:8080' failed:
Error in connection establishment: net::ERR_CERT_COMMON_NAME_INVALID
What you should be doing is connecting to Nginx, which is listening on port 443 and then let Nginx proxy the request. There must be some code on your page somewhere which is specifying port 8080.
Get rid of it.

Related

Why PHP Ratchet Websocket connection with Nginx is not working?

I'm running websocket using PHP Ratchet. Here is code :
$allowed_origins = ['localhost', '127.0.0.1', '95.179.194.135'];
$host = '95.179.194.135';
$app = new Ratchet\App($host, 8080, '0.0.0.0');
$app->route('/', new Cmc, $allowed_origins);
$app->run();
Web server is Nginx . Here is nginx configuration:
upstream websocket {
server 95.179.194.135:8080;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /etc/ssl/certs/localhost.crt;
ssl_certificate_key /etc/ssl/private/localhost.key;
index index.php index.html;
root /var/www/html;
server_name 95.179.194.135;
location /cmchat {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}
}
Ratchet service is running fine as I checked in terminal.
Here is javascript code to connect to websocket:
const wsChat = new WebSocket("ws://95.179.194.135/cmchat");
but its never connected.
telnet connection working :
telnet 95.179.194.135 8080 this command showing this:
Trying 95.179.194.135...
Connected to 95.179.194.135.
Escape character is '^]'.
but when from javascript its never connected.
can anyone help me to find find issue why its not working.
thanks

Newbie - how do I configure NGINX to only serve request from a specific domain? [duplicate]

Is it possible to allow only users typing in xxxxxx.com (fictive), so they should make a DNS-lookup and connect. And block users who uses my public ip to connect ?
Configuration:
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name xxxxxxx.com;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/jenkins.access.log;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Fix the “It appears that your reverse proxy set up is broken" error.
proxy_pass http://10.0.11.32:80;
proxy_read_tenter code hereimeout 360;
proxy_redirect http://10.0.11.32:80 https://xxxxxxx.com;
}
}
The $http_host parameter is set to the value of the Host request header. nginx uses that value to select a server block. If a server block is not found, the default server is used, which is either marked as default_server or is the first server block encountered. See this documentation.
To force nginx to only accept named requests, use a catch all server block to reject anything else, for example:
server {
listen 80 default_server;
return 403;
}
server {
listen 80;
server_name www.example.com;
...
}
With the SSL protocol, it depends on whether or not you have SNI enabled. If you are not using SNI, then all SSL requests pass through the same server block, in which case you will need to use an if directive to test the value of the $http_host value. See this and this for details.

Nginx: WebSocket wildcard location

I use a nginx instance in front of a Go service.
I want to redirect anything on port 80 to https. [done]
All (non-websocket) https requests at /* should go to https://localhost:8443/* [done]
All websocket https requests at /ws/* should go to https://localhost:8443/ws/* [missing]
My current config:
ssl_certificate ...
ssl_certificate_key ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.mydomain.com mydomain.com;
add_header Strict-Transport-Security "max-age=31536000";
location /ws { <--- This only works for /ws but not /ws/app1
proxy_pass http://localhost:8443/ws;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / { <--- Catches anything, even without wildcard ?!
proxy_pass http://localhost:8443;
}
}
server {
listen 443 ssl;
server_name *.mydomain.com;
return 444;
}
Why is this necessary ? Well, as I understand, you have to set the upgrade headers explicitly, so I guess you have to specify another location.
Ideally, I would just use one location, but then websockets are blocked (because upgrade headers never make it to the Go service...)
I'm not a nginx expert, so bear with me =).
[EDIT]
I got it working now. I'm not sure if its ok to always set_header Upgrade/Connection, even if it's not a websocket request, but my Go service doesn't give a ****, so it works for me =]
ssl_certificate ...
ssl_certificate_key ...
ssl_ciphers ...
ssl_prefer_server_ciphers on;
server {
listen 80;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name www.mydomain.com mydomain.com;
add_header Strict-Transport-Security "max-age=31536000";
location / { <--- Catches anything, even without wildcard ?!
proxy_pass http://localhost:8443;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
server {
listen 443 ssl;
server_name *.mydomain.com;
return 444;
}
Check out the article at https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
You are not using any location_match, so the match is a prefix match.
Use ~ as the location match modifier to have it interpreted as a regular expression.
The line location /ws should match every query starting with /ws.

Nginx reverse proxy, only allow connection from hostname not ip

Is it possible to allow only users typing in xxxxxx.com (fictive), so they should make a DNS-lookup and connect. And block users who uses my public ip to connect ?
Configuration:
server {
listen 80;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name xxxxxxx.com;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/jenkins.access.log;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Fix the “It appears that your reverse proxy set up is broken" error.
proxy_pass http://10.0.11.32:80;
proxy_read_tenter code hereimeout 360;
proxy_redirect http://10.0.11.32:80 https://xxxxxxx.com;
}
}
The $http_host parameter is set to the value of the Host request header. nginx uses that value to select a server block. If a server block is not found, the default server is used, which is either marked as default_server or is the first server block encountered. See this documentation.
To force nginx to only accept named requests, use a catch all server block to reject anything else, for example:
server {
listen 80 default_server;
return 403;
}
server {
listen 80;
server_name www.example.com;
...
}
With the SSL protocol, it depends on whether or not you have SNI enabled. If you are not using SNI, then all SSL requests pass through the same server block, in which case you will need to use an if directive to test the value of the $http_host value. See this and this for details.

Nginx server name issue

In my Nginx configuration, I would like to keep one service to be accessible with http, while all the others should be accessed through https, and forced to ssl when trying to connect with http. This is my config:
server{
server_name localhost;
listen 80;
proxy_http_version 1.1;
location /services/ {
proxy_pass http://localhost:47440/;
}
listen / {
rewrite ^ https://$server_name$request_uri? permanent;
}
server{
server_name localhost_ssl;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/mycert.crt;
ssl_certificate_key /etc/nginx/ssl/mycert.key;
proxy_http_version 1.1;
location /db/ {
proxy_pass http://localhost_ssl:8084/;
}
}
My problem is that when trying to reload I get this error:
host not found in upstream "localhost_ssl" in /etc/nginx/nginx.conf:46
Any idea of why this happens?
It seems your DNS resolver is failing for some reason.
Try adding:
options single-request
to /etc/resolv.conf
This causes IPv6/v4 lookups to be done sequentially.
You got this error because nginx can't find the host "localhost_ssl". Indeed it doesn't exist unless you specify it with upstream directive (or in the hosts file I think).
You should set it to proxy_pass http://localhost:8084/; assuming your service is really listening on 127.0.0.1:8084.
Furthermore you may want to replace listen / { with location / {.
UPDATE : If you access your server with your IP (you don't have a domain name), then you can remove server_name directive :
server {
listen 80;
proxy_http_version 1.1;
location /services {
proxy_pass http://localhost:47440/;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri?; # Replace $server_name by $host
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/mycert.crt;
ssl_certificate_key /etc/nginx/ssl/mycert.key;
proxy_http_version 1.1;
location /db {
proxy_pass http://localhost:8084/;
proxy_set_header Host $host;
}
}
That config redirects requests received on port 80 to 443 if they don't match location /services. Requests received on port 443 are proxied if they match location /db.
But is this what you really want to achieve ? I mean a request on port 443 for /test would not match any location as there is only /db.

Resources