Use dotenvx with Docker

Use dotenvx with Docker

Initial setup

Install the necessary web server libraries in the language of your choice.

npm install express --save

Create a simple Hello World program.

// index.js
const express = require('express')
const app = express()
const PORT = process.env.PORT || 3000

app.get('/', (req, res) => {
  res.send(`Hello ${process.env.HELLO || ''}`)
})

app.listen(PORT, () => {
  console.log(`Server running on port:${PORT}`)
})

Create a Dockerfile.

# Dockerfile
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

Create .dockerignore.

.dockerignore

# .dockerignore
.env.keys

Build and run it with Docker.

docker build -t app . && docker run -it --init --rm -p 3000:3000 app
docker container

Once built, your app will say 'Hello [blank]' as it doesn't have a way to access the environment variable yet. Let's do that next.

Run dotenvx

Install dotenvx to your Dockerfile and prepend your app command with dotenvx run --.

# Dockerfile
FROM node:20
WORKDIR /app

# Install dotenvx
RUN curl -fsS https://dotenvx.sh/ | sh

COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000

# Prepend dotenvx run
CMD ["dotenvx", "run", "--", "node", "index.js"]

Create a .env file in the root of your project.

.env

# .env
HELLO="World"

Build and run it with Docker.

docker build -t app . && docker run -it --init --rm -p 3000:3000 app
localhost:$PORT

Your app will say Hello World. The values from your .env file were successfully injected into your env. That covers local development. Let's solve for production next.

Add production environment

Create a .env.production file in the root of your project.

.env.production

# .env.production
HELLO="production"

Use dotenvx to load your .env.production file by updating your Dockerfile CMD.

CMD ["dotenvx", "run",  "--env-file=.env.production", "--", "node", "index.js"]

Build and run it with Docker.

docker build -t app . && docker run -it --init --rm -p 3000:3000 app
localhost:$PORT

Your app will say Hello production, simulating production. Solid. Let's encrypt your secrets next.

Encrypt production

dotenvx set HELLO production -f .env.production --encrypt

Your .env.production file is now encrypted, and you have a .env.keys file.

.env.production

#/-------------------[DOTENV_PUBLIC_KEY]--------------------/
#/            public-key encryption for .env files          /
#/       [how it works](https://dotenvx.com/encryption)     /
#/----------------------------------------------------------/
DOTENV_PUBLIC_KEY_PRODUCTION="0354d5293e40f78b8b44d6b5ded92719ef99d119a79093d6babd0ef9e80a9a7667"

# .env.production
HELLO="encrypted:BGo+chylmSbkHeDsn9gPy5LYvYUUpTstaUr8hDU0lgp4ssyH2MXav43ww+B3WNaYLZQpJdJdJ2F8qLbV4vDolF42ETQFu/xxhKA2/MRxiC/Vd1s/DMDjm9RSHOCQ5YHywLrUY9UySesbn58="

.env.keys

#/------------------!DOTENV_PRIVATE_KEYS!-------------------/
#/ private decryption keys. DO NOT commit to source control /
#/     [how it works](https://dotenvx.com/encryption)       /
#/----------------------------------------------------------/

# .env.production
DOTENV_PRIVATE_KEY_PRODUCTION="3c54363a4a678042d298660e2038df68aaa4a9383048d913d0e6db15e137020d"

We're ready to inject the encrypted .env.production secrets into Docker run.

Set decryption key

Set DOTENV_PRIVATE_KEY_PRODUCTION on Docker using the production key in your .env.keys file.

docker build -t app . && docker run -e "DOTENV_PRIVATE_KEY_PRODUCTION=3c54363a4a678042d298660e2038df68aaa4a9383048d913d0e6db15e137020d" -it --init --rm -p 3000:3000 app

Your docker instance starts and env is successfully injected using the encrypted contents of .env.production.

[[email protected]] injecting env (2) from .env.production
Server running on port:3000

Visit your url and it says Hello production.

docker container

Great job! That's pretty much it. See the bonus section(s) below to go a little deeper.


Bonus

Try changing the value of .env.production to your name.

dotenvx set HELLO Mot --encrypt

Commit .env.production safely to code and re-run your Docker container.