
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).