43

I tried to use SSL by Node.js but it doesn't work because permission denied.

try {
var TLSoptions = {
    key: fs.readFileSync("/etc/letsencrypt/live/domain.work/privkey.pem"),
    cert: fs.readFileSync("/etc/letsencrypt/live/domain.work/cert.pem")
};

https.createServer(TLSoptions, app).listen(port, host, function() {
   console.log("TLS Website started.")
}); catch(e) {
    console.log(e)
}

=>

{ Error: EACCES: permission denied, open '/etc/letsencrypt/live/domain.work/privkey.pem'
at Object.fs.openSync (fs.js:663:18)
... (Librarys dump)
errno: -13,
code: 'EACCES',
syscall: 'open',
path: '/etc/letsencrypt/live/domain.work/privkey.pem' }

So I tried re-make files of *.pem.

rm -f /etc/letsencrypt/live
rm -f /etc/letsencrypt/archive    
rm -f /etc/letsencrypt/renewal
sudo ./letsencrypt-auto certonly -a standalone -d domain.work

and check file authority.

/etc/letsencrypt/live/domain.work$ ls -lsa
total 12
4 drwxr-xr-x 2 root root 4096 Jan  3 21:56 .
4 drwx------ 3 root root 4096 Jan  3 21:56 ..
0 lrwxrwxrwx 1 root root   37 Jan  3 21:56 cert.pem -> 
../../archive/domain.work/cert1.pem
0 lrwxrwxrwx 1 root root   38 Jan  3 21:56 chain.pem -> 
../../archive/domain.work/chain1.pem
0 lrwxrwxrwx 1 root root   42 Jan  3 21:56 fullchain.pem -> 
../../archive/domain.work/fullchain1.pem
0 lrwxrwxrwx 1 root root   40 Jan  3 21:56 privkey.pem -> 
../../archive/domain.work/privkey1.pem

/etc/letsencrypt/archive/domain.work$ ls -lsa
total 24
4 drwxr-xr-x 2 root root 4096 Jan  3 21:56 .
4 drwx------ 3 root root 4096 Jan  3 21:56 ..
4 -rw-r--r-- 1 root root 1789 Jan  3 21:56 cert1.pem
4 -rw-r--r-- 1 root root 1647 Jan  3 21:56 chain1.pem
4 -rw-r--r-- 1 root root 3436 Jan  3 21:56 fullchain1.pem
4 -rw-r--r-- 1 root root 1708 Jan  3 21:56 privkey1.pem

but It is not resolved and I cannot find any mistakes and problems.
How to resolve this problem?

kraftwerk
  • 443
  • 1
  • 4
  • 6
  • run the script as root? – James Lalor Jan 03 '18 at 13:51
  • Looks like you need to make executable your script. For instance: `chmod +x /root/letsencrypt.sh`. But by your post I cant undestand where you got error. Maybe you can add more details? – Mikita Melnikau Jan 03 '18 at 14:13
  • yes. I ran the script `sudo npm start`. – kraftwerk Jan 03 '18 at 20:14
  • Letsencrypt makes valid cert/key that is proved by Apache SSL. though using Node.js, it failed by permission denied. – kraftwerk Jan 03 '18 at 20:22
  • Solution #4 of the accepted answer by SamGoody worked for me, but the commands did not work for me as stated. Instead I had to `s`witch `u`ser to root using `su root` and then `cd` into `/etc/letsencrypt/...` and use a combination of the Solution #4 commands and `ls -la` to check the group states. Otherwise I found the files weren't changed as required ! Once I had confirmed with `ls -la` that the file groups had indeed been changed, it worked perfectly. –  Jan 10 '22 at 15:56

5 Answers5

108

When you use sudo to issue the certificates, they will be owned by root. Since node is not run as root, and the permissions on the certificate folder do not allow them to be opened by anyone except the owner, your node app cannot see them.

To understand the solution, let us assume node is running as the user nodeuser

You can get your user on ubuntu by using : whoami or ps aux | grep node

Solution #1 (temporary):
You could switch the owner of the certificates to your node user.
$ sudo chown nodeuser -R /etc/letsencrypt
However, this may break any other items that look at the cert, such as Nginx or Apache.
It will also only last till your next update, which is no more than 90 days. On the other hand, whatever script you have that renews the cert can also set the owner.

Solution #2 (do not do this):
Run node as root.
sudo node index.js
This will run node as a root user, which means that the terribly insecure surface of node can access everything on your system. Please don't do this.

Solution #3 (do not do this either):
Open the certificates to everyone.
The certificates are stored in /etc/letsencrypt/archive/${domain}/cert1.pem, and are linked to from /etc/letsencrypt/live/${domain}/cert1.pem.

All folders in both of these paths are +x, meaning that all users on the system can open the folders, with the exception of the "live" and "archive" folders themselves.
You can make those open as well by changing their permissions.

$ sudo chmod +x /etc/letsencrypt/live
$ sudo chmod +x /etc/letsencrypt/archive

This is bad as it allows access from other unexpected sources. Generally opening folders to everyone is a bad idea.

Solution #4 (do this):
On the other hand, you can create a limited group, and allow the permissions to only be opened for them.

// Create group with root and nodeuser as members
$ sudo addgroup nodecert
$ sudo adduser nodeuser nodecert
$ sudo adduser root nodecert

// Make the relevant letsencrypt folders owned by said group.
$ sudo chgrp -R nodecert /etc/letsencrypt/live
$ sudo chgrp -R nodecert /etc/letsencrypt/archive

// Allow group to open relevant folders
$ sudo chmod -R 750 /etc/letsencrypt/live
$ sudo chmod -R 750 /etc/letsencrypt/archive

That should allow node to access the folders with the certs, while not opening it to anyone else.

You should then reboot or at least logout and in after these changes.
(Many changes to permission and groups require a new session, and we had issues with PM2 until reboot.)

On ec2 instance you can do sudo reboot.

Should something go wrong and you want to revert to original settings follow this

// Delete Group
$ sudo groupdel nodecert
    
// Reset Permission
$ sudo chown -R :root /etc/letsencrypt/live
$ sudo chown -R :root /etc/letsencrypt/archive
    
// Check Permissions
$ sudo ll /etc/letsencrypt/
Community
  • 1
  • 1
SamGoody
  • 13,758
  • 9
  • 81
  • 91
  • Is it dangerous to run `sudo adduser peter nodecert`? This makes user `peter` to have access to the certificates as well. And since `pm2`/`node` will run using `peter` privileges, all is ok, right? – Peter Mar 29 '19 at 15:03
  • 6
    `nodeuser` is an arbitrary name of the user running node. If node is running under peter, than you would do `sudo adduser peter nodecert`. You should limit peter from doing other things besides running node, since if node is compromised, the attacker will be able to do anything peter could - which could be substantial. – SamGoody Apr 01 '19 at 14:59
  • 3
    @SamGoody Your solution worked for me. I like the way you answered it with all the bad options, too. Very educational. Would it have been okay to only do the `/etc/letsencrypt/live` folder? – Chroaster Jun 18 '19 at 20:07
  • @Chroaster Thanks. The /live folder does not actually contain the certs, it only contains links to the archive folder, and therefore you need to set the permissions on the archive folder as well. To see that /live is symlinks, do `$ ls -l /etc/letsencrypt/live/{your-site}`. Notice that every file has an arrow pointing to ../archive/ – SamGoody Jun 19 '19 at 10:05
  • @SamGoody Sorry I meant `/etc/letsencrypt/archive`. And it was really just out of curiosity. I can just try it later :) – Chroaster Jun 19 '19 at 19:47
  • 9
    I just noticed something. `chmod 710` as shown above gives execute permission to the `nodecert` group but that still gives me the EACCES error. I gave read access as well using `sudo chmod -R 750 /etc/letsencrypt/archive` and `sudo chmod -R 750 /etc/letsencrypt/live` and the error went away. Makes sense since we want node to read the key/cert, not execute them. (Also added `-R` to make the permission changes propagate down to the files themselves.) – Chroaster Jun 19 '19 at 20:23
  • In order to traverse a folder, you need execute permissions but not read permissions. It seems you had an issue with the files themselves not having read permissions, and setting all files and folders to 750 solved that issue, but it is not such a good idea to give files execute perms unless you have a reason to. Instead, set the folders to 710, and the files to 740. – SamGoody Jun 21 '19 at 09:22
  • You can find out what user is running node with `ps aux | grep node`. Since node is generally started manually with `node (or npx, pm2, etc) index.js`, the user is the one who started node, which is known. – SamGoody Sep 03 '19 at 08:08
  • 6
    @Chroaster: thanks for the `-R` recursive pointer. I also did this for the `sudo chgrp -R nodecert /etc/letsencrypt/live` in order to work. – ofri cofri Apr 20 '20 at 18:17
  • 4
    This helped we with several changes (I'm under CentOS 7). Had to use `sudo groupadd nodecert` instead of `sudo addgroup nodecert`. Had to use `sudo usermod -a -G nodecert username` instead of `sudo adduser username nodecert`. Had to do `sudo chgrp -R nodecert /etc/letsencrypt/archive` (looks like the -R was the key) after everything was done. After that, node could access the files, hurrah! – Alex Kogan Sep 17 '20 at 09:09
  • 1
    I would like to add that this solution did not work for me until I added READ rights to the nodecert group for the folder "../archive/myDomain". (chmod g+r). I am using a nodejs https server with letsencrypt. – Ben Oct 18 '20 at 09:52
  • My Centos 7 experience mirrors Ben -- I had to open the `.pem` files to reading by the group. I did `chmod 640 *.pem` in the `../archive/myDomain` directory. – Tom Stambaugh Aug 17 '21 at 21:30
  • @SamGoody (above): Since the files themselves are just keys, I don't think they need to or should be executable. I think the correct permissions are `chmod 640 *.pem`. I'm nervous about opening the private key to the group (that's not allowed in .ssh configuration), but it seems to work and in my case (a very tightly locked down EC2 instance) there's minimal danger (I think!). – Tom Stambaugh Aug 17 '21 at 21:35
  • did i do something wrong? - if i switch user to nodeuser to run my node stuff, nodeuser doesn't have node or pm2 installed - should these be reinstalled when logged in as nodeuser? – andygoestohollywood Sep 11 '21 at 06:11
  • @andygoestohollywood My guess is that you are using [nvm](https://github.com/nvm-sh/nvm) or something that installs all packages (including global ones) into the local user's directory. If so than you will need to reinstall everything for each new user you create an connect from. – SamGoody Sep 12 '21 at 10:52
  • Should something go wrong follow this to rollback // Delete Group - $ sudo groupdel nodecert // Reset Permission - $ sudo chown -R :root /etc/letsencrypt/live $ sudo chown -R :root /etc/letsencrypt/archive // Check Permissions - $ sudo ll /etc/letsencrypt/ – DragonFire Dec 25 '21 at 02:52
11

I'm not familiar with Node.js, but it's clearly the same permissions problem as with PostgreSQL. So the same solution should work fine. This allows you to leave the permissions on /etc/letsencrypt as they are :

  • copy the certificates to your Node.js directory
  • chown the copied files to your "node" user

You can have a script doing that in /etc/letsencrypt/renewal-hooks/deploy which will be called everytime you renew your certificates.

Example /etc/letsencrypt/renewal-hooks/deploy/10-certbot-copy-certs :

#!/bin/bash

domain=domain.work # using your example name
node_dir=/path/to/cert_copies
node_user=nodeuser

cp /etc/letsencrypt/live/$domain/{fullchain,privkey}.pem "$node_dir"/
chown $node_user "$node_dir"/*.pem
mivk
  • 13,452
  • 5
  • 76
  • 69
  • thanks, this did the job. somehow i couldn't even access the files in /etc/letsencrypt/live/yoursite/fullchain.pem and privkey.pem when i was owner (except root) – David Nov 12 '19 at 13:46
  • Will this work when certs are renewed – DragonFire Dec 22 '21 at 02:24
  • @DragonFire : yes, the scripts under .../renewal-hooks/deploy/ run every time the certs are renewed (as the name suggests) – mivk Dec 22 '21 at 09:54
2

This worked for me:

  1. Copy all pem files that you need into the root folder of your project:

sudo cp /etc/letsencrypt/live/www.your-domain.com/privkey.pem /home/your-username/your-server-directory/privkey.pem

  1. Read the files like so:
.createServer(
    {
      key: fs.readFileSync("privkey.pem"),
      cert: fs.readFileSync("cert.pem"),
    },
  1. Grant permissions:

sudo chown your-username -R privkey.pem

gignu
  • 1,763
  • 1
  • 14
  • 24
2

I was using ec2-user on Amazon Linux 2 instance and had the same problem. This worked for me:

sudo chown ec2-user -R /etc/letsencrypt
Jamshid Hashimi
  • 7,639
  • 2
  • 28
  • 27
0

The above top answer by @SamGoody didn't work for me since it didn't set all the group permissions. It worked after I setup the nodecert group as he suggested like this

$ sudo addgroup nodecert
$ sudo adduser nodeuser nodecert
$ sudo adduser root nodecert

and then did

$ sudo nautilus

and clicked down to /etc/letsencrypt then right clicked "Properties" and changed the group permissions manually to nodecert "Access files" in the following two folders and their domain name subfolders

/etc/letsencrypt/live
/etc/letsencrypt/archive

Also changed group permissions manually to nodecert "Read-only" for all contained files and symlinks.