Hi, just recently I configured the development environment by using @forestadmin/agent
. When I try to configure production environment, it doesn’t work and I am stuck with the message:
It looks like the URL is not responding
package.json
{
"name": "cbl",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
"start_dev": "nodemon ./bin/www",
"docker": "docker-compose up --build"
},
"dependencies": {
"@forestadmin/agent": "1.0.0-beta.43",
"@forestadmin/datasource-sequelize": "1.0.0-beta.34",
"bcryptjs": "^2.4.3",
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
"date-and-time": "^2.4.1",
"debug": "~2.6.9",
"dotenv": "^16.0.1",
"express": "~4.17.3",
"express-validator": "^6.14.2",
"handlebars": "^4.7.7",
"handlebars-helpers": "^0.10.0",
"http-errors": "~1.6.3",
"jade": "^0.29.0",
"jsonwebtoken": "^8.5.1",
"mailgun.js": "^8.0.0",
"moment": "^2.29.4",
"morgan": "~1.9.1",
"mysql2": "^2.3.3",
"nodemailer": "^6.7.7",
"passport": "^0.6.0",
"passport-jwt": "^4.0.0",
"rand-token": "^1.0.1",
"sequelize": "^6.21.3",
"sequelize-auto": "^0.8.8"
},
"devDependencies": {
"nodemon": "^2.0.19",
"sequelize-cli": "^6.4.1"
}
}
app.js
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const { createAgent } = require('@forestadmin/agent');
const {
createSequelizeDataSource,
} = require('@forestadmin/datasource-sequelize');
require('dotenv').config();
const cors = require('cors');
const sequelizeInstance = require('./src/db/models/index').sequelize;
var indexRouter = require('./src/routes/index');
var authRouter = require('./src/routes/api/auth');
var usersRouter = require('./src/routes/api/users');
var ceremonyRouter = require('./src/routes/api/ceremony');
var questionRouter = require('./src/routes/api/questions');
var app = express();
console.log(process.env.FOREST_AUTH_SECRET);
console.log(process.env.FOREST_AGENT_URL);
console.log(process.env.FOREST_ENV_SECRET);
console.log(process.env.NODE_ENV);
// Create your Forest Admin agent
// This must be called BEFORE all other middlewares on the express app
createAgent({
authSecret: process.env.FOREST_AUTH_SECRET,
agentUrl: process.env.FOREST_AGENT_URL,
envSecret: process.env.FOREST_ENV_SECRET,
isProduction: process.env.NODE_ENV === 'production',
})
.addDataSource(createSequelizeDataSource(sequelizeInstance))
.mountOnExpress(app)
.start();
let allowedOrigins = [/\.forestadmin\.com$/, /localhost:\d{4}$/];
if (process.env.ALLOWED_CORS) {
allowedOrigins = allowedOrigins.concat(process.env.ALLOWED_CORS.split(','));
}
var corsOptions = {
origin: allowedOrigins,
};
app.use(cors(corsOptions));
// view engine setup
app.set('views', path.join(__dirname, 'src/views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//Routes
app.use('/', indexRouter);
app.use('/api', indexRouter);
app.use('/api/auth', authRouter);
app.use('/api/users', usersRouter);
app.use('/api/ceremony', ceremonyRouter);
app.use('/api/questions', questionRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
// set port, listen for requests
const PORT = process.env.NODE_DOCKER_PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
module.exports = app;
/src/db/models/index.js
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../../config/database.js')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], {
...config,
host: process.env.USING_DOCKER ? 'host.docker.internal' : config.host,
});
} else {
sequelize = new Sequelize(config.database, config.username, config.password, {
...config,
host: process.env.USING_DOCKER ? 'host.docker.internal' : config.host,
});
}
sequelize
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch((err) => {
console.error('Unable to connect to the database:', err);
});
fs.readdirSync(__dirname)
.filter((file) => {
return (
file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js'
);
})
.forEach((file) => {
const model = require(path.join(__dirname, file))(
sequelize,
Sequelize.DataTypes
);
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
module.exports = db;
src/config.database.js
require('dotenv').config();
module.exports = {
development: {
username: process.env.MYSQLDB_USER,
password: process.env.MYSQLDB_ROOT_PASSWORD,
database: process.env.MYSQLDB_DATABASE,
host: '127.0.0.1',
port: process.env.MYSQLDB_LOCAL_PORT,
dialect: 'mysql',
},
test: {
username: process.env.MYSQLDB_USER_STAGE,
password: process.env.MYSQLDB_ROOT_PASSWORD_STAGE,
database: process.env.MYSQLDB_DATABASE_STAGE,
host: '127.0.0.1',
dialect: 'mysql',
},
production: {
username: process.env.MYSQLDB_USER_PROD,
password: process.env.MYSQLDB_ROOT_PASSWORD_PROD,
database: process.env.MYSQLDB_DATABASE_PROD,
host: '127.0.0.1',
dialect: 'mysql',
},
};
bin/www
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('cbl-backend:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
The app is deployed on aws ec2 ubuntu without docker. I use docker only on localhost. MySQL is used as a database and I use only default configuration, there is no require_secure_transport
. I turned off the firewall on ubuntu for now.
3306 port is opened in inbound connections:
I can connect to production database from my local machine:
Pm2 is used as a process manager, here are the logs where you can see that process.env.FOREST_AUTH_SECRET
, process.env.FOREST_AGENT_URL
, process.env.FOREST_ENV_SECRET
, process.env.NODE_ENV
exist:
There are no errors in pm2 error log file:
.forestadmin-schema.json
file is on the server:
this is the DATABASE_URL
:
What’s wrong? How can I debug this issue?