I am running an nginx server and a node express web server, using daemontools, setup to communicate over Unix Domain Sockets. There's just a few problems:
If I chgrp and chmod g+w the socket file, everything works fine. Is there a way to set this up so that the node application's socket file gets generated with the correct permissions for nginx to be able to write to it without compromising the security independence of one application or the other? I would even be okay with adding nginx to the node user's group, if there was still a way to set the permissions on the socket file so that it would be group writable.
The traditional UNIX system calls are blocking. For example: accept() blocks the caller until a connection is present. If no messages space is available at the socket to hold the message to be transmitted, then send() normally blocks.
Valid socket types in the UNIX domain are: SOCK_STREAM, for a stream-oriented socket; SOCK_DGRAM, for a datagram-oriented socket that preserves message boundaries (as on most UNIX implementations, UNIX domain datagram sockets are always reliable and don't reorder datagrams); and (since Linux 2.6.
Unix domain sockets are often twice as fast as a TCP socket when both peers are on the same host. The Unix domain protocols are not an actual protocol suite, but a way of performing client/server communication on a single host using the same API that is used for clients and servers on different hosts.
Unix Domain Socket uses a local file on the device. It does not require network ports to be open, instead the Linux system controls who can have access to the file for communication. This is advantageous as you can assign permissions that suit the way you want to set up the system.
@Bobby's answer left me with connect() to unix:/run/static0.sock failed (13: Permission denied)
in nginx. Chmod 777 was the trick. Here's my solution [building on his]:
var fs = require('fs');
var http = require('http');
var process = require('process');
var express = require('express')
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
var sock = process.argv[2];
fs.stat(sock, function(err) {
if (!err) { fs.unlinkSync(sock); }
http.createServer(app).listen(sock, function(){
fs.chmodSync(sock, '777');
console.log('Express server listening on ' + sock);
});
});
Run like:
$ node server.js /run/static0.sock
Express server listening on /run/static0.sock
Maybe I am too late.
As a complement of your own answer there is a solution not having to add the nginx user to the node group.
Create a directory only for the socket file, assign it to the node user and www-data (or whatever group the nginx is) group and set the group-id bit (SGID) on that directory.
mkdir -p /var/lib/yourapp/socket
chown nodeuser:nginxgroup /var/lib/yourapp/socket
chmod g+rxs /var/lib/yourapp/socket
All files created inside this directory will automatically be owned by the nginxgroup group.
I was able to get it working by adding nginx to the node user's primary group:
gpasswd -a nginx node
And then starting the express server using the following:
// Create the server
fs.stat(listen, function(err) {
if (!err) { fs.unlinkSync(sock); }
http.createServer(app).listen(sock, function(){
fs.chmodSync(sock, '775');
console.log('Express server listening on ' + listen);
});
});
I don't really feel like this is a valid solution, just a hack. Express wasn't built with deleting and setting file perms in mind, and it especially bugs me to have to add the nginx user to the node user's primary group. If there were ever a compromise of the nginx account, the attacker could conceivably have access to all of the application's source, and an avenue to try endless attacks on the code using the socket. The best that I can do is set the umask to 077 for the node user and try to get 100% coverage with a chmod 600 on every file and chmod 700 on every directory, or set the group to the non-default for the user on everything.
That said, I would still appreciate any ideas.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With