Parse server on Debian Buster (10)

I need to have a backend to my Flutter application with a huge amount of reads/writes to database, let’s say a million requests / day.

The simple solution is to use Firebase, but it’s limited to 20K writes per day on free plan.

Another backend options are:

Back4app – hosted parse server service actually, 10K / month requests for free.

Amazon AWS Amplify – 1 year tier for free, then you need to pay.

Backendless – again limited storage and limited number of requests.

Appwrite – promising project, but you can run it only from docker and the minimal requirement is 2GB RAM (i’ve tried to run it on 1GB VPS, but got out-of-memory). And almost all of the memory is taken by clamd antivirus, but i don’t need it actually neither for my mobile app nor for my backend and database.

MongoDB Atlas – again limited storage.

So, i’ve decided to “reanimate” an old backend player – Parse Server Community Edition. It was maybe the 1st player in mobile backend services, created by Facebook and it was free, so i think many projects still use it.

So, for my platform i’ll use Debian 10 “Buster”, but i think but not sure all of the instructions will be compatible with Ubuntu and other Debian clones.

Step 1 – Install Node.js

Let’s add a Node JS packages repository to apt:

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -

Let’s read the script output and follow the commands provided:

sudo apt-get install -y nodejs

This will install Node.js itself.

Now let’s install yarn package manager as recommended.

curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -

echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

sudo apt-get update && sudo apt-get install yarn

Step 2 -Install PostgreSQL server

apt -y install postgresql

sudo systemctl enable postgresql

sudo -s

su - postgres

createuser getbook24

createdb getbook24 -O getbook24

psql getbook24

# alter user getbook24 with password 'Lib0x2020#';

Step 3 – Setup Parse Server

Let’s install Parse server:

$ cd ~

$ mkdir parse-server

$ cd parse-server

sh <(curl -fsSL https://raw.githubusercontent.com/parse-community/parse-server/master/bootstrap.sh)

The script will ask the destination folder, AppName, App Id and Master Key. It have an option to autogenerate App ID and Master Key, but it didn’t work for me.

Edit config.json file – review server configuration and add a keys for application:

nano -w config.json

{
  "appId": "2c8PP9ZpLAf0gMbluhYNQXysW6sS8S2s",
  "masterKey": "Wc7IX0GwDW1wffnK2AQ45kFMM8CL1HRk",
  "clientKey": "GXUgDDHySdXYgQP5nYGP1sC8gpRalJ1T",
  "appName": "Getbook24",
  "cloud": "./cloud/main",
  "databaseURI": "postgres://<db_user>:<db_pass>@localhost:5432/getbook24"
}

Change db_user and db_pass to your postgres db parameters.

To create strong keys, i’ve used https://randomkeygen.com/

Let’s start our Parse sever:

nohup parse-server config.json &

Check if server is running:

telnet localhost 1337

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
quit
HTTP/1.1 400 Bad Request
Connection: close

Connection closed by foreign host.

Step 4 – Setup Parse Dashboard

I prefer to install parse dashboard on my local machine and connect it to running parse server.

Install parse dashboard with yarn:

yarn global add parse-dashboard

Next, configure parse dashboard settings:

nano parse-darshboard-config.json

Add the following configuration. Notice that appId and masterKey must to be the same as in parse server configuration in config.json:

{
  "apps": [
    {
      "serverURL": "http://<your internal server IP>:1337/parse",
      "appId": "2c8PP9ZpLAf0gMbluhYNQXysW6sS8S2s",
      "masterKey": "Wc7IX0GwDW1wffnK2AQ45kFMM8CL1HRk",
      "allowInsecureHTTP": "true",
      "appName": "MyApp1"
    }
  ],
 "users": [
    {
      "user":"admin",
      "pass":"password"
    }
  ],
  "iconsFolder": "icons"
}

Start parse dashboard:

nohup parse-dashboard --dev --config parse-dashboard-config.json &

Now you can go to

http://localhost:4040

and check the Parse dashboard UI. If you ran parse dashboard on your local machine you can skip the login – just remove “users” section in config file.

Step 5 – Install and configure PM2

$ sudo npm install -g pm2

To run parse server with PM2 we need to create a startup script.

$ sudo nano index.js:

// Example express application adding the parse-server module to expose Parse
// compatible API routes.

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

var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;

if (!databaseUri) {
  console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({
  databaseURI: databaseUri || 'postgres://parse:Lib0x2020$@localhost:27017/dev',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || '2c8PP9ZpLAf0gMbluhYNQXysW6sS8S2s',
  masterKey: process.env.MASTER_KEY || 'Wc7IX0GwDW1wffnK2AQ45kFMM8CL1HRk', //Add your master key here. Keep it secret!
  clientKey: process.env.CLIENT_KEY || 'GXUgDDHySdXYgQP5nYGP1sC8gpRalJ1T',
  serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',  // Don't forget to change to https if needed
  liveQuery: {
    classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
  }
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var app = express();

// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
  res.status(200).send('I dream of being a website.  Please star the parse-server repo on GitHub!');
});

// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
  res.sendFile(path.join(__dirname, '/public/test.html'));
});

var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
    console.log('parse-server-example running on port ' + port + '.');
});

// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);

Change your keys and database connection settings regarding to your setup.

Check if your server starting correctly:

$ npm start

If all works normally, shut down the parse server with Ctrl-C. Now let’s add it to PM2:

$ pm2 start index.js

Step 6 – Encrypt connection

Setting up Apache server and Letsencrypt certificate is out of the scope of this article, I’ve already running apache secured with letsencrypt certificates. What i need it to redirect my internal queries to my parse server running on localhost.

$ sudo nano /etc/letsencrypt/options-ssl-apache.conf

 SSLProxyEngine on

 ProxyPass "/dashboard/" http://localhost:4040/dashboard/
 ProxyPassReverse "/dashboard/"   http://localhost:4040/dashboard/

 ProxyPass "/parse/" http://localhost:1337/parse/
 ProxyPassReverse "/parse/" http://localhost:1337/parse/

Restart apache to load changes:

$ sudo systemctl restart apache2

This is the end of this article.

In the next articles i will show you how to connect and use parse server in command line Dart application (to load and update data from external sources) and in mobile Flutter application (to load and show the data from parse server).

Leave a Reply