Modify process.env for a running NodeJS process

Warning: this might not solve the problem you have. For me, I wanted to change the config on a HTTP server without restarting it and although I’ll show you how to edit process.env, if you have other vars that read values from process.env then they won’t be updated.


If you have a running process and you need to change values in process.env, I’ll show you the steps. There’s a screencast and a text version of the same steps.


Screencast


Text version

Starting a demo process
For this example we need a process to attach to. We’ll just use a nodejs REPL:

BLAH=11 node

Find the PID of the node process
We need the process ID (PID) of the nodejs process. One way to find it is with

$ ps -e | grep node
1234 pts/21   00:00:01 node

For this example, we’ll use 1234 as the value for the PID.

Option 1: connect a local debugger to the process

If you have a shell on the machine that’s running the process, you can use the CLI debugger. Note: if the current user isn’t root or the user that started the process, you’ll have to sudo the command.

node inspect -p <pid>
# so for our example
node inspect -p 1234

Once in the debugger, jump into a REPL with:

debug> repl

Option 2: enable remote debug mode for the nodejs process

Even though the process wasn’t started as debug, we can trigger debug mode with the USR1 signal. Note: if the current user isn’t root or the user that started the process, you’ll have to sudo the command.

kill -s SIGUSR1 <pid>
# so for our example
kill -s SIGUSR1 1234

You won’t get any output from the command, but if you can see the process logs (or the output of the repl process), you’ll see two lines printed about debugging enabled

Debugger listening on ws://127.0.0.1:9229/357cd2bb-f87a-4eb6-8107-ef3b36b4b042
For help, see: https://nodejs.org/en/docs/inspector

The server most likely doesn’t expose the 9229 debug port, but we can workaround that by using port forwarding through an SSH tunnel. If we assume this is the command you use to ssh to the machine:

ssh -i /some/key.pem [email protected]

…then you’d modify that command to forward the 9229 port on the remote machine to port 30001 on your local machine:

ssh -i /some/key.pem -nNT -L 30001:localhost:9229 [email protected]

…then you can connect the Chrome, vscode, etc debugger on your local machine to port 30001.

Check the value of the env
Before we change the value, let’s check what it is.

> process.env.BLAH
'11'

Edit the value
It’s just the syntax you’d always use.

process.env.BLAH = '22'

Check the change took effect
Run the “Check the value” step again.

Disconnect
If you’re in the CLI debugger, use Control+D to exit the repl and the debugger.


Things I’m not sure of:


How to automate the debug commands

The process debug uses JSON over websockets to communicate. If we know the commands and can send them into the websocket, we can write a script to automated it.

Unfortunately you can’t use curl to send data through a websocket, you can only check the initial handshake works. To actually send data, we need something that understands websockets. I use wscat here but there are others (websocat for example).

Thanks to this GitHub comment we have a way to see what messages are sent when using the debugger interactively. To use this in the example above, you’d run the debugger with

NODE_DEBUG=inspect node inspect -p 1234

…and then send something in the REPl. For our command to check the value of the env var, we’ll see the message and response are:

> {"id":10,"method":"Runtime.evaluate","params":{"expression":"process.env.BLAH\n","objectGroup":"node-inspect","generatePreview":true}}
< {"id":10,"result":{"result":{"type":"string","value":"11"}}}

Then if we change the var, the message and response are:

> {"id":10,"method":"Runtime.evaluate","params":{"expression":"process.env.BLAH = '22'\n","objectGroup":"node-inspect","generatePreview":true}}
< {"id":10,"result":{"result":{"type":"string","value":"22"}}}

Now we have a tool to send data into the websocket and we know the message to send, we can automate it with

wscat \
  -c ws://127.0.0.1:9229/357cd2bb-f87a-4eb6-8107-ef3b36b4b042 \
  -x '{"id":10,"method":"Runtime.evaluate","params":{"expression":"process.env.BLAH = \"55\"\n","objectGroup" :"node-inspect","generatePreview":true}}'

comments powered by Disqus