Reputation:
I deployed a Nodejs application, the backend of it so far to Heroku. I am getting an application error in the browser. When I run heroku logs
, I see this error:
Error: Cannot find module './config/keys'
So I run a heroku run 'ls -al'
and I see this:
Running ls -al on ⬢ murmuring-temple-46226... up, run.3327 (Free)
total 284
drwx------ 8 u6811 dyno 4096 Apr 21 11:41 .
drwxr-xr-x 15 root root 4096 Apr 18 13:09 ..
-rw------- 1 u6811 dyno 21 Apr 21 11:37 .gitignore
drwx------ 3 u6811 dyno 4096 Apr 21 11:37 .heroku
drwx------ 2 u6811 dyno 4096 Apr 21 11:37 .profile.d
-rw------- 1 u6811 dyno 0 Apr 21 11:37 @1
-rw------- 1 u6811 dyno 574 Apr 21 11:37 index.js
drwx------ 2 u6811 dyno 4096 Apr 21 11:37 models
drwx------ 261 u6811 dyno 12288 Apr 21 11:38 node_modules
-rw------- 1 u6811 dyno 235090 Apr 21 11:37 package-lock.json
-rw------- 1 u6811 dyno 565 Apr 21 11:37 package.json
drwx------ 2 u6811 dyno 4096 Apr 21 11:37 routes
drwx------ 2 u6811 dyno 4096 Apr 21 11:37 services
I do see that my config
folder is not in that list of files and folders up top, but that can be because in my .gitignore
file, I have it so it will ignore the keys.js
file, or could it be I have it referenced wrong in my code base?
This is how I require it in index.js
:
const express = require('express');
const mongoose = require('mongoose');
const cookieSession = require('cookie-session');
const passport = require('passport');
const keys = require('./config/keys');
require('./models/User');
require('./services/passport');
mongoose.connect(keys.mongoURI);
const app = express();
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.cookieKey]
})
);
app.use(passport.initialize());
app.use(passport.session());
require('./routes/authRoutes')(app);
const PORT = process.env.PORT || 5000;
app.listen(PORT);
and this is how I reference it in services/passport.js
:
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const mongoose = require('mongoose');
const keys = require('../config/keys');
const User = mongoose.model('users');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(null, user);
});
});
// passport.use() is a generic register to make Passport
// aware of new strategy
// creates a new instance to authenticate users
passport.use(
new GoogleStrategy(
{
clientID: keys.googleClientID,
clientSecret: keys.googleClientSecret,
callbackURL: '/auth/google/callback'
},
(accessToken, refreshToken, profile, done) => {
User.findOne({ googleId: profile.id }).then(existingUser => {
if (existingUser) {
// we already have a record with given profile id
done(null, existingUser);
} else {
// we dont have a user record with this id, make a new record
new User({ googleId: profile.id })
.save()
.then(user => done(null, user));
}
});
}
)
);
What is the best practice here for deploying an application successfully to Heroku with a config/keys.js
folder file structure that houses API keys and other creds?
Upvotes: 3
Views: 3326
Reputation: 15453
What I would do is remove keys.js
from your .gitignore
file. Create two other files in your config
folder. One for development and one for production. Put your keys in the development file and then have .gitignore
ignore that development file.
Then in your keys.js
file create an if
statement like so:
// keys.js - figure out what set of credentials to return
if (process.env.NODE_ENV === 'production') {
// we are in production - return the prod set of keys
module.exports = require('./prod');
} else {
// we are in development - return the dev keys!!
module.exports = require('./dev');
}
Then in your production file you are going to do as my colleague above suggested, but probably more like this:
// prod.js - production keys here
module.exports = {
googleClientID: process.env.GOOGLE_CLIENT_ID,
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET,
cookieKey: process.env.COOKIE_KEY
};
If you are also connecting to a database like MongoDB then you want to add that as well above like this, mongoURI: process.env.MONGO_URI
.
The last thing you have to do is make sure all these different environment variables are defined on your Heroku environment variables.
Setting all these things up is straightforward, you just have to know where to look on Herokus’ control interface or do them via command line terminal as my colleague above suggested. If you are pretty comfortable with command line terminal, go ahead and follow the steps above, if not then go inside your browser and navigate to dashboard.heroku.com
Find the application you have created for your app, click on it.
Then click on the settings tab and you should see Config Variables. Click on reveal Config Variables and that should give you an interface to set up all the different variables you want to add to your application.
One by one you add in a key and its corresponding value
So first do the GOOGLE_CLIENT_ID
, copy that and enter it as the key, then go grab your credentials. You should already have your credentials copy pasted somewhere.
Do the same for COOKIE_KEY
and if you are using Mongo, `MONGO_URI
So now you can hide config variables and no one will be able to see them.
As you might imagine you don’t want anyone getting into your heroku account. If someone gets into your heroku account, I don’t know what to tell you.
Now you can deploy your application by committing your code using git and deploy it using git as well.
Do a git status
that shows your files and folders.
git add .
git commit -m “completed environment variables”
git push
git push heroku master
You should be good to go after this with that error having gone away.
Upvotes: 2
Reputation: 4710
You do the right thing by ignoring the configuration file.You should always keep away your secret keys from github and bitbucket. The right way in this situation is to set your keys as an environment variables on heroku. You can use these commands:
# Add new variable
heroku config:set COOKIE_KEY=somekey
# Remove variable
heroku config:unset COOKIE_KEY
# Get all environment variables
heroku config
# Get environment variable by name
heroku config:get COOKIE_KEY
In your application, you can access these variables using process.env
object:
process.env.COOKIE_KEY
process.env.GOOGLE_CLIENT_ID
process.env.GOOGLE_CLIENT_SECRET
Note: the configuration keys must be in uppercase
Upvotes: 1