Deploy Parse Server, MongoDB and Parse Dashboard on Ubuntu 18.04

Parse is an excellent mBaaS developed by Parse Inc. (acquired by Facebook) then abandoned/Open Sourced. It has an active community and can help you build your mobile apps very fast.

Parse has SDKs for native android, javascript/react native and is very straightforward to integrate into your app.

If you would like to avoid the hassle of setting up and maintaing your own infrastructure, I recommend using back4app.com which provides good support for parse and offer a fair free tier service:

Ideal for developing, learning and prototyping
No credit card required10k Requests
250 MB Database
1 GB Transfer
1 GB Storage

In my case, I always prefer maintaining my own servers and infrastructure. This tutorial can be automated by using ansible. but for now we will do the installation manually.

# Install and secure MongoDB

On a fresh Ubuntu 18.04 VPS, use apt to install the latest available version of MongoDB:

$ sudo apt install -y mongodb

After the install finishes, check that the service is running:

$ sudo systemctl status mongodb

Output:

● mongodb.service - An object/document-oriented database
   Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2020-03-09 09:59:32 UTC; 11s ago
     Docs: man:mongod(1)
 Main PID: 31917 (mongod)
    Tasks: 23 (limit: 2291)
   CGroup: /system.slice/mongodb.service
           └─31917 /usr/bin/mongod --unixSocketPrefix=/run/mongodb --config /etc/mongodb.conf

[...] systemd[1]: Started An object/document-oriented database.

Let’s also check that we can connect to mongodb:

$ mongo
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
	http://docs.mongodb.org/
Questions? Try the support group
	http://groups.google.com/group/mongodb-user
> db.runCommand({ connectionStatus: 1 })
{
	"authInfo" : {
		"authenticatedUsers" : [ ],
		"authenticatedUserRoles" : [ ]
	},
	"ok" : 1
}

Important: don’t forget to secure access to the database

Check that mongodb only accepts connections from localhost. If you want to make the server accessible over the Internet, you can tweak your firewall settings. I recommend however connecting to the db server through an ssh tunnel.

$ sudo nano /etc/mongodb.conf

bind_ip = 127.0.0.1 should be uncommented

Configure Access Control

By Default, no authentication is configured to access the db server.

$ mongo 
2020-03-09T09:59:34.649+0000 I CONTROL  [initandlisten] 
2020-03-09T09:59:34.649+0000 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2020-03-09T09:59:34.649+0000 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2020-03-09T09:59:34.649+0000 I CONTROL  [initandlisten] 

On the mongo console, switch to the admin database and create a new user:

> use admin
> db.createUser(
  {
    user: "superuser",
    pwd: "changeMeToAStrongPassword",
    roles: [ "root" ]
  }
)
Successfully added user: { "user" : "superuser", "roles" : [ "root" ] }

Shutdonwn server:

> db.shutDownServer()

Edit /etc/mongod.conf to enable authorizations:

#auth = true <------- uncomment and save the file

Now you can log back in to the mongo cli and create your desired dbs and app specific users:

$ mongo admin -u <admin_user> -p <admin_password>
...
> use <new_db_name>
...
> db.createUser(...)

# Install Parse Server

This step requires having nodejs installed on your machine. 

We are going to use the Node.js application that uses the Parse Server module on Express and can be easily deployed to various infrastructure providers. This app is available here: https://github.com/parse-community/parse-server-example

Make sure to have git installed:

user@zeitouna:~# apt install git
Reading package lists... Done
Building dependency tree       
Reading state information... Done
git is already the newest version (1:2.17.1-1ubuntu0.5).

Clone the parse-server-example and install dependencies:

$ cd /opt
$ git clone https://github.com/ParsePlatform/parse-server-example.git
$ cd parse-server-example
$ npm install

Create a .env file:

PARSE_SERVER_DATABASE_URI=mongodb://localhost:27017/<database_name>
PARSE_SERVER_APPLICATION_ID=<your_app_desired_id>
PARSE_SERVER_MASTER_KEY=<generate a strong master key and keep it scret!>
PARSE_SERVER_URL=http://localhost:1337/parse

Now to be able to load these variables from the .env file, we need to make some changes to the index.js file:

$ npm install --save dotenv

Open index.js:

var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');

// read .env file
var dotenv = require('dotenv');
dotenv.config();

...
// also edit variable names accordingly!

You need to add the .env file to .gitignore

...

# env file
.env

...

# Configuring the Server

First it is important to impose a strong user password policy. In order to do this, edit index.js:

// add the following to the new ParseServer({}) object
passwordPolicy: {
// enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1 digit
    validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, 
    // a callback function to be invoked to validate the password
    validatorCallback: (password) => { return validatePassword(password) },
    doNotAllowUsername: true, // optional setting to disallow username in passwords
    maxPasswordHistory: 5,
    resetTokenValidityDuration: 24*60*60, // expire after 24 hours
}

# Manage server with pm

Install pm globally:

$ sudo npm install -g pm2

Run the server with pm:

$ pm2 start index.js
$ pm2 startup
$ pm2 save

# Install and configure Parse Dashboard

Parse Dashboard
Parse Dashboard UI

Install the dashboard from npm.

$ npm install -g parse-dashboard

Edit index.js to configure parse-server and parse-dashboard to run on the same server/port:

...

var ParseDashboard = require('parse-dashboard');

var api = new ParseServer({
	// Parse Server settings
});

var options = { allowInsecureHTTP: false };

var dashboard = new ParseDashboard({
	// Parse Dashboard settings
}, options);

var app = express();

// make the Parse Server available at /parse
app.use('/parse', api);

....

var dashApp = express();

// make the Parse Dashboard available at /dashboard
dashApp.use('/dashboard', dashboard);  

// Parse Server plays nicely with the rest of your web routes
dashApp.get('/', function(req, res) {  
  res.status(200).send('Parse Dashboard App');
});

var httpServerDash = require('http').createServer(dashApp);  
httpServerDash.listen(4040, function() {  
    console.log('dashboard-server running on port 4040.');
});

We configure Parse Dashboard with one app and one user:

"apps": [
    {
      "serverURL": process.env.PARSE_SERVER_URL,
      "appId": process.env.PARSE_SERVER_APPLICATION_ID,
      "masterKey": process.env.PARSE_SERVER_URL,
      "appName":  "applicationName"
    }
  ],
 "users": [
    {
      "user": process.env.PARSE_DASHBOARD_USERNAME, 
      "pass": process.env.PARSE_DASHBOARD_PASSWORD
    }
  ],
  "trustProxy": 1

Don’t forget to edit .env with the new variables PARSE_DASHBOARD_USERNAME and PARSE_DASHBOARD_PASSWORD

# Installing NGINX and Let’s Encrypt

We will be setting up a reverse proxy to redirect all https traffic to parse server. In order to make this happen, we need to install nginx and configure SSL certificates from Let’s Encrypt.

Intsall nginx:

$ sudo apt install nginx

Then, add certbot repository:

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt install python-certbot-nginx

Generate the SSL certificate:

$ sudo certbot -d <app.domain.com> --nginx

Now we are going to set the reverse proxy to route traffic to Parse. Open the corresponding nginx conf file:

...

# Pass requests for /parse/ to Parse Server instance at localhost:1337
       location /parse/ {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-NginX-Proxy true;
            proxy_pass http://localhost:1337;
            proxy_ssl_session_reuse off;
            proxy_set_header Host $http_host;
            proxy_redirect off;
       }

# Pass requests for /dashboard/ to Parse Server instance at localhost:4040
location /dashboard/ {
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-NginX-Proxy true;
         proxy_pass http://localhost:4040/dashboard/;
         proxy_ssl_session_reuse off;
         proxy_set_header Host $http_host;
         proxy_redirect off;
}

...

restart nginx:

$ sudo service nginx restart

# Conclusion

Login to https://app.domain.com/dashboard and you should be able to view and connect to Parse Dashboard correctly: