Parse is a Mobile Backend as a Service platform, owned by Facebook since 2013. In January of 2016, Parse announced that its hosted services would shut down completely on January 28, 2017.

Fortunately, Parse has also released an open source API server, compatible with the hosted service’s API, called Parse Server. Parse Server is under active development, and seems likely to attract a large developer community. It can be be deployed to a range of environments running Node.js and MongoDB.

This guide focuses on migrating a pre-existing Parse application to a standalone instance of Parse Server running on Ubuntu 14.04. It uses TLS/SSL encryption for all connections, using a certificate provided by Let’s Encrypt, a new Certificate Authority which offers free certificates. It includes a few details specific to DigitalOcean and Ubuntu 14.04, but should be broadly applicable to systems running recent Debian-derived GNU/Linux distributions.

Warning: It is strongly recommended that this procedure first be tested with a development or test version of the app before attempting it with a user-facing production app. It is also strongly recommended that you read this guide in conjunction with the official migration documentation.


This guide builds on How To Run Parse Server on Ubuntu 14.04. It requires the following:

  • An Ubuntu 14.04 server, configured with a non-root sudo user
  • Node.js 5.6.x
  • MongoDB 3.0.x
  • A domain name pointing at the server
  • A Parse App to be migrated
  • Nginx installed and configured with SSL using Let’s Encrypt certificates. How To Secure Nginx with Let’s Encrypt on Ubuntu 14.04 will walk you through the process.

The target server should have enough storage to handle all of your app’s data. Since Parse compresses data on their end, they officially recommend that you provision at least 10 times as much storage space as used by your hosted app.

Step 1 – Configure MongoDB for Migration

Parse provides a migration tool for existing applications. In order to make use of it, we need to open MongoDB to external connections and secure it with a copy of the TLS/SSL certificate from Let’s Encrypt. Start by combining fullchain1.pem and privkey1.pem into a new file in /etc/ssl:

  • sudo cat /etc/letsencrypt/archive/domain_name/{fullchain1.pem,privkey1.pem} | sudo tee /etc/ssl/mongo.pem

You will have to repeat the above command after renewing your Let’s Encrypt certificate. If you configure auto-renewal of the Let’s Encrypt certificate, remember to include this operation.

Make sure mongo.pem is owned by the mongodb user, and readable only by its owner:

  • sudo chown mongodb:mongodb /etc/ssl/mongo.pem
  • sudo chmod 600 /etc/ssl/mongo.pem

Now, open /etc/mongod.conf in nano (or your text editor of choice):

  • sudo nano /etc/mongod.conf

Here, we’ll make several important changes.

First, look for the bindIp line in the net: section, and tell MongoDB to listen on all addresses by changing to Below this, add SSL configuration to the same section:

# network interfaces
  port: 27017
    mode: requireSSL
    PEMKeyFile: /etc/ssl/mongo.pem

Next, under # security, enable client authorization:

# security
  authorization: enabled

Finally, the migration tool requires us to set the failIndexKeyTooLong parameter to false:


  failIndexKeyTooLong: false

Note: Whitespace is significant in MongoDB configuration files, which are based on YAML. When copying configuration values, make sure that you preserve indentation.

Exit and save the file.

Before restarting the mongod service, we need to add a user with the admin role. Connect to the running MongoDB instance:

  • mongo --port 27017

Create an admin user and exit. Be sure to replace sammy with your desired username and password with a strong password.

use admin
  user: "sammy",
  pwd: "password",
  roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]

Restart the mongod service:

  • sudo service mongod restart

Step 2 – Migrate Application Data from Parse

Now that you have a remotely-accessible MongoDB instance, you can use the Parse migration tool to transfer your app’s data to your server.

Configure MongoDB Credentials for Migration Tool

We’ll begin by connecting locally with our new admin user:

  • mongo --port 27017 --ssl --sslAllowInvalidCertificates --authenticationDatabase admin --username sammy --password

You should be prompted to enter the password you set earlier.

Once connected, choose a name for the database to store your app’s data. For example, if you’re migrating an app called Todo, you might use todo. You’ll also need to pick another strong password for a user called parse.

From the mongo shell, give this user access to database_name:

  • use database_name
  • db.createUser({ user: "parse", pwd: "password", roles: [ "readWrite", "dbAdmin" ] })

Initiate Data Migration Process

In a browser window, log in to Parse, and open the settings for your app. Under General, locate the Migrate button and click it:

Parse App Settings: General: Migrate

You will be prompted for a MongoDB connection string. Use the following format:


For example, if you are using the domain, with the user parse, the password foo, and a database called todo, your connection string would look like this:


Don’t forget ?ssl=true at the end, or the connection will fail. Enter the connection string into the dialog like so:

Parse App: Migration Dialog

Click Begin the migration. You should see progress dialogs for copying a snapshot of your Parse hosted database to your server, and then for syncing new data since the snapshot was taken. The duration of this process will depend on the amount of data to be transferred, and may be substantial.

Parse App: Migration Progress

Parse App: Migration Process

Verify Data Migration

Once finished, the migration process will enter a verification step. Don’t finalize the migration yet. You’ll first want to make sure the data has actually transferred, and test a local instance of Parse Server.

Parse App: Finished Migration, Waiting for Finalization

Return to your mongo shell, and examine your local database. Begin by accessing database_name and examining the collections it contains:

  • use database_name
  • show collections
Sample Output for Todo App
Todo _Index _SCHEMA _Session _User _dummy system.indexes

You can examine the contents of a specific collection with the .find() method:

  • db.ApplicationName.find()
Sample Output for Todo App
> db.Todo.find() { "_id" : "hhbrhmBrs0", "order" : NumberLong(1), "_p_user" : "_User$dceklyR50A", "done" : false, "_acl" : { "dceklyR50A" : { "r" : true, "w" : true } }, "_rperm" : [ "dceklyR50A" ], "content" : "Migrate this app to my own server.", "_updated_at" : ISODate("2016-02-08T20:44:26.157Z"), "_wperm" : [ "dceklyR50A" ], "_created_at" : ISODate("2016-02-08T20:44:26.157Z") }

Your specific output will be different, but you should see data for your app. Once satisfied, exit mongo and return to the shell:

  • exit

Step 3 – Install and Configure Parse Server and PM2

With your app data in MongoDB, we can move on to installing Parse Server itself, and integrating with the rest of the system. We’ll give Parse Server a dedicated user, and use a utility called PM2 to configure it and ensure that it’s always running.

Install Parse Server and PM2 Globally

Use npm to install the parse-server utility, the pm2 process manager, and their dependencies, globally:

  • sudo npm install -g parse-server pm2

Create a Dedicated Parse User and Home Directory

Instead of running parse-server as root or your sudo user, we’ll create a system user called parse:

  • sudo useradd --create-home --system parse

Now set a password for parse:

  • sudo passwd parse

You’ll be prompted to enter a password twice.

Now, use the su command to become the parse user:

  • sudo su parse

Change to parse’s home directory:

  • cd ~

Write or Migrate a Cloud Code File

Create a cloud code directory:

  • mkdir -p ~/cloud

Edit /home/parse/cloud/main.js:

  • nano ~/cloud/main.js

For testing purposes, you can paste the following:

Parse.Cloud.define('hello', function(req, res) {

Alternatively, you can migrate any cloud code defined for your application by copying it from the Cloud Code section of your app’s settings on the Parse Dashboard.

Exit and save.

Retrieve Keys and Write /home/parse/ecosystem.json

PM2 is a feature-rich process manager, popular with Node.js developers. We’ll use the pm2 utility to configure our parse-server instance and keep it running over the long term.

You’ll need to retrieve some of the keys for your app. In the Parse dashboard, click on App Settings followed by Security & Keys:

Parse Dashboard: App Settings: Security & Keys

Of these, only the Application ID and Master Key are required. Others (client, JavaScript, .NET, and REST API keys) may be necessary to support older client builds, but, if set, will be required in all requests. Unless you have reason to believe otherwise, you should begin by using just the Application ID and Master Key.

With these keys ready to hand, edit a new file called /home/parse/ecosystem.json:

  • nano ecosystem.json

Paste the following, changing configuration values to reflect your MongoDB connection string, Application ID, and Master Key:

  "apps" : [{
    "name"        : "parse-wrapper",
    "script"      : "/usr/bin/parse-server",
    "watch"       : true,
    "merge_logs"  : true,
    "cwd"         : "/home/parse",
    "env": {
      "PARSE_SERVER_CLOUD_CODE_MAIN": "/home/parse/cloud/main.js",
      "PARSE_SERVER_DATABASE_URI": "mongodb://parse:password@your_domain_name:27017/database_name?ssl=true",
      "PARSE_SERVER_APPLICATION_ID": "your_application_id",
      "PARSE_SERVER_MASTER_KEY": "your_master_key",

The env object is used to set environment variables. If you need to configure additional keys, parse-server also recognizes the following variables:


Exit and save ecosystem.json.

Now, run the script with pm2:

  • pm2 start ecosystem.json
Sample Output
... [PM2] Spawning PM2 daemon [PM2] PM2 Successfully daemonized [PM2] Process launched ┌───────────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├───────────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ parse-wrapper │ 0 │ fork │ 3499 │ online │ 0 │ 0s │ 13.680 MB │ enabled │ └───────────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app

Now tell pm2 to save this process list:

  • pm2 save
Sample Output
[PM2] Dumping processes

The list of processes pm2 is running for the parse user should now be stored in /home/parse/.pm2.

Now we need to make sure the parse-wrapper process we defined earlier in ecosystem.json is restored each time the server is restarted. Fortunately, pm2 can generate and install a script on its own.

Exit to your regular sudo user:

  • exit

Tell pm2 to install initialization scripts for Ubuntu, to be run as the parse user, using /home/parse as its home directory:

  • sudo pm2 startup ubuntu -u parse --hp /home/parse/
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Generating system init script in /etc/init.d/
[PM2] Making script booting at startup...
[PM2] -ubuntu- Using the command:
      su -c "chmod +x /etc/init.d/ && update-rc.d defaults"
 System start/stop links for /etc/init.d/ already exist.
[PM2] Done.

Step 4 – Install and Configure Nginx

We’ll use the Nginx web server to provide a reverse proxy to parse-server, so that we can serve the Parse API securely over TLS/SSL.

In the prerequisites, you set up the default server to respond to your domain name, with SSL provided by Let’s Encrypt certificates. We’ll update this configuration file with our proxy information.

Open /etc/nginx/sites-enabled/default in nano (or your editor of choice):

  • sudo nano /etc/nginx/sites-enabled/default

Within the main server block (it should already contain a location / block) add another location block to handle the proxying of /parse/ URLs:

. . .
        # 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;

Exit the editor and save the file. Restart Nginx so that changes take effect:

  • sudo service nginx restart
* Restarting nginx nginx ...done.

Step 5 – Test Parse Server

At this stage, you should have the following:

  • A TLS/SSL certificate, provided by Let’s Encrypt
  • MongoDB, secured with the Let’s Encrypt certificate
  • parse-server running under the parse user on port 1337, configured with the keys expected by your app
  • pm2 managing the parse-server process under the parse user, and a startup script to restart pm2 on boot
  • nginx, secured with the Let’s Encrypt certificate, and configured to proxy connections to https://your_domain_name/parse to the parse-server instance

It should now be possible to test reads, writes, and cloud code execution using curl.

Note: The curl commands in this section should be harmless when used with a test or development app. Be cautious when writing data to a production app.

Writing Data with a POST

You’ll need to give curl several important options:

Option Description
-X POST Sets the request type, which would otherwise default to GET
-H "X-Parse-Application-Id: your_application_id" Sends a header which identifies your application to parse-server
-H "Content-Type: application/json" Sends a header which lets parse-server know to expect JSON-formatted data
-d '{json_data} Sends the data itself

Putting these all together, we get:

curl -X POST \
  -H "X-Parse-Application-Id: your_application_id" \
  -H "Content-Type: application/json" \
  -d '{"score":1337,"playerName":"Sammy","cheatMode":false}' \
Sample Output

Reading Data with a GET

Since curl sends GET requests by default, and we’re not supplying any data, you should only need to send the Application ID in order to read some sample data back:

  • curl -H "X-Parse-Application-Id: your_application_id" https://your_domain_name/parse/classes/GameScore
Sample Output
{"results":[{"objectId":"BNGLzgF6KB","score":1337,"playerName":"Sammy","cheatMode":false,"updatedAt":"2016-02-17T20:53:59.947Z","createdAt":"2016-02-17T20:53:59.947Z"},{"objectId":"0l1yE3ivB6","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T03:57:00.932Z","createdAt":"2016-02-18T03:57:00.932Z"},{"objectId":"aKgvFqDkXh","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T04:44:01.275Z","createdAt":"2016-02-18T04:44:01.275Z"},{"objectId":"zCKTgKzCRH","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T16:56:51.245Z","createdAt":"2016-02-18T16:56:51.245Z"},{"objectId":"YpxFdzox3u","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-02-18T18:03:43.188Z","createdAt":"2016-02-18T18:03:43.188Z"}]}

Executing Example Cloud Code

A simple POST with no real data to https://your_domain_name/parse/functions/hello will run the hello() function defined in /home/parse/cloud/main.js:

curl -X POST \
  -H "X-Parse-Application-Id: your_application_id" \
  -H "Content-Type: application/json" \
  -d '{}' \
Sample Output

If you have instead migrated your own custom cloud code, you can test with a known function from main.js.

Step 6 – Configure Your App for Parse Server and Finalize Migration

Your next step will be to change your client application itself to use the Parse Server API endpoint. Consult the official documentation on using Parse SDKs with Parse Server. You will need the latest version of the SDK for your platform. As with the curl-based tests above, use this string for the server URL:


Return to the Parse dashboard in your browser and the Migration tab:

Parse App: Migration Process

Click the Finalize button:

Parse Migration Finalization Dialog

Your app should now be migrated.

Conclusion and Next Steps

This guide offers a functional starting point for migrating a Parse-hosted app to a Parse Server install on a single Ubuntu system, such as a DigitalOcean droplet. The configuration we’ve described should be adequate for a low-traffic app with a modest userbase. Hosting for a larger app may require multiple systems to provide redundant data storage and load balancing between API endpoints. Even small projects are likely to involve infrastructure considerations that we haven’t directly addressed.

In addition to reading the official Parse Server documentation and tracking the GitHub issues for the project when troubleshooting, you may wish to explore the following topics:


  • Thank you for your guide.
    I have followed it step by step, omitting the ssl part as we’ll be using http.

    When I try to call Parse server on my droplet using my appId i get always get a 404. If I don´t provide the appId a just get {“error”:“unauthorised”}

    Can you help point me in the right direction?

    • Could you elaborate on your setup a bit? Are you still proxying through Nginx, or just hitting the parse-server endpoint directly?

      • PM2 is setup to start parse-server on reboot. I hit the parse-server endpoint directly.

        • One thing that comes to mind is that, as written, parse-server is expecting to serve from the root of http://your_domain_or_ip:1337/, not from http://your_domain_or_ip:1337/parse, so if you’ve got the /parse in your requests, it’ll fail. This distinction tripped me up a few times.

          If that’s not it, a Pastebin or Gist of your ecosystem.json (minus Master Key, database URI, and any other sensitive data) and some sample curl requests might be helpful.

  • This looks great Brennen! :)

    Thanks a lot for all the work involved, I hope to give this a test soon.

    Just a small note, under “Reading Data with a GET”, in the first example text, you have your testing domain instead of “<your_domain>”. Might trip people copy/pasting who don’t see it :)

  • I keep getting

    script not found: /usr/bin/parse-server

    Any way to fix this? This is the only thing stopping the server from running

  • I setup my parse server according to Parse’s website, then I found this article and followed the instruction to setup Nginx so I can communicate using HTTPS. However, I found some strange behaviour and wondering if you can provide some insight.

    • When I hit the server without SSL, e.g. http://[my domain]:1337/parse/classes/gamescore, everything is good.
    • However, when I hit the server with SSL, e.g. https://[my domain]/parse/classes/gamescore, the response is “Cannot GET /classes/GameScore”

    I am certain that I am hitting my Parse server as if I turn my server off the GET will receive a different response. Also, if I define a route in my index.js (as according to Parse’s example) I can actually reach it, for example, with the following code inserted in index.js (again, as according to Parse’s example), I get the desired response:
    app.get(’/’, function(req, res) {
    res.status(200).send(‘I dream of being a web site.’);

    Wondering if you have some insight into this strange behaviour.


  • Thanks for this tutorial. I have managed to get all the way through, up to the last step. When I call my cloud functions or I only get 502 Bad Gateway response.

    When I run tail -f /var/log/nginx/error.log

    I get

    2016/02/24 07:04:34 [error] 15253#0: *5 connect() failed (111: Connection refused) while connecting to upstream, client: XXX.XXX.XXX.XXX, server:, request: "GET /parse/functions/hello HTTP/1.1", upstream: "", host: ""
  • In order to make Push Notification work, I had to go into my parse-server (/usr/local/bin/parse-server) and add something like:

        options.push = {
          "ios": [
              "pfx": '/home/parse/mycert.p12', 
              "bundleId": 'my_bundle',
              "production": false // Dev

    Is there a way to do this in ecosystem.json?

    Thanks in advance!

    • Is there a way to do this in ecosystem.json?

      Good question. I didn’t think so at first, but the situation has changed quite a bit since I wrote this guide in February. From a quick glance at the parse-server repo and the wiki page on Push configuration, it seems like you could define a PARSE_SERVER_PUSH containing some JSON and accomplish the same thing.

      I’m specifically looking at this bit of option handling:

        "push": {
          env: "PARSE_SERVER_PUSH",
          help: "Configuration for push, as stringified JSON. See",
          action: function(opt) {
            return JSON.parse(opt)

      …so maybe try something like:

            "PARSE_SERVER_PUSH": '{ "ios": [ { "pfx": "/home/parse/mycert.p12", "bundleId": "my_bundle", "production": false } ] }',

      …with the latest parse-server. This gets a little bit silly, since it’s JSON inside a string in a JSON file which defines an environment variable. At this stage you’re likely better off defining options as command-line parameters, or (probably best) using Parse Server by mounting the module on a custom Express app, as described in the Parse Server Guide on the official wiki.

  • I finished this tutorial and everything works except cloud code. When I do a query in my cloud code the code just stops. When I Executed Example Cloud Code from this tutorial It worked well. Any help would be appreciated… The problem is not with just this query, everytime I set a query in cloud code it just stops… not even going to Success or Error

    Parse.Cloud.afterSave("_User", function(request) {
      var user = request.object;
      query = new Parse.Query(Parse.Role);
      query.equalTo("name", "Standard");
      console.log("the code just stops here...");
      query.first ( {
        success: function(object) {
, { useMasterKey: true });
        error: function(error) {
  • Thank you for this amazing guide.
    I have followed every step (i left encryption part away, don’t need it for the time being). i ’ve managed to migrate from Parse to my mongodb with success.
    The problem is that it seems impossible to get to the parse server. i’ve configured ecosystem.json with my application’s info then run pm2. the daemon seems good but still i can’t see any proccess listening to 1337 or 80 (80 wouldnt work i’ve skipped nginx). so i cannot test it properly. any kind of help would be so much appreciated! Thank you in advance

    • try to use a command pm2 logs (on the parse user) and it will show you where it is running, or if it is running....

      • Hello MazelTov the error i got is:
        parse-wrapper-0 (err): You must provide a serverURL! and its obvious. but where should i input this information? Thank you for all your help

        • i have problem with this one two, because serverURL is required if you wanna run cloud code and I have been strugling with this for over a week.... try here sudo nano /usr/lib/node_modules/parse-server/bin/parse-server

        • I really dont know… my ecosystem looks exactly the same as here and everything is running except cloud code, I think you should set this url only in nginx

        • OK I just updated my parse server to the latest version and I am getting the same error as you :-D if you will find the answer please share it

          • i just tried to add it here sudo nano /usr/bin/parse-server (i did the global instalation) and added this line in the else statement options.serverURL = ‘http://…’; and I get rid of this error and parse is running again, the cloud code not…

          • This solved the error and now while i am trying to execute a curl code to get results from db i get {“error”:“unauthorized”}. ring any bells?

  • I used this article to install parse server & migrate. I am able to run the curl command in the localhost:1337 and it works like a charm. However when I run from outside the server I get Cannot POST /functions/hello - I looked up the nginx logs and I see a 404. Nginx config is exactly the same as described in this post.

    Any help would be greatly appreciated. Thanks!

  • Thanks for tutorial. I need to validate User list. How one lists _User and _Role collections?

    show collections
    2016-03-24T14:43:22.310-0400 E QUERY [thread1] TypeError: db._User is undefined :

  • Hi guys,
    Thank you for your guide.
    I’m trying to migrate mi parse app top DigitalOcean

    But in Step 2 – Configure MongoDB for Migration I have an problem, when I’m trying to run mongo –port 27017 I got this result

    2016-03-25T05:38:59.582-0400 W NETWORK  Failed to connect to, reason: errno:111 Connection refused
    2016-03-25T05:38:59.583-0400 E QUERY    Error: couldn't connect to server (, connection attempt failed
        at connect (src/mongo/shell/mongo.js:181:14)
        at (connect):1:6 at src/mongo/shell/mongo.js:181
    exception: connect failed

    I’m new in set-up servers, and new in SSH commands, don’t know what I’m doing wrong,

    Thanks a lot,

    • I have had the same issue. Deleting mongo and reinstalled it fixed it, though I sometimes still can’t access it via command line.

    • Same here. I deleted mongo and reinstalled it, but it still fails to connect. I get the following status right after starting:

      $ service mongod status
      mongod stop/waiting
    • I’ve got the same problem. Yesterday it worked, today not anymore… Try to make sense of that…

      I tried different thing to understand the core reason.
      It appears that if I comment these lines :
      mode: requireSSL
      PEMKeyFile: /etc/ssl/mongo.pem

      Then, it works fine. But, obviously, it’s not normal. I would be glad if somebody could explain what is the problem and how to solve it.
      I checked if the file /etc/ssl/mongo.pem exists, and it does. So, I can’t understand why it causes an issue.

      I read here an interesting point about encrypted private key (which seems to be the case in this scenario). It requires passPhrase definition (link to go deeper about it in the previous link). But, where/what is this passPhrase ??

  • Great Guide i am having problem while running this query
    $sudo chown mongodb:mongodb /etc/ssl/mongo.pem
    error :
    chown: invalid user: `mongodb:mongodb’

  • I am having problem in configuring mongod.conf file could anyone send me his conf file

  • Bro i am facing this error
    [thread1] Error: socket exception [CLOSED] for :
    while running
    mongo –port 27017 –ssl –sslAllowInvalidCertificates –authenticationDatabase admin –username sammy –password

  • Everything was smooth until the point where I logged into the mongo shell to do show collections and I got the following error:

    "errmsg" : "not authorized on <dbname> to execute command { listCollections: 1.0, filter: {} }",

    I double checked the createUser commands and they look okay. Any thoughts?

    • I have the same problem, any thoughts ??

      • I had this issue as well and was able to resolve it by granting the correct roles to the db user that was created during the “Step 2 – Configure MongoDB for Migration” portion of the tutorial :

        db.grantRolesToUser("<your_user_name>",[{role: "dbOwner", db: "<your_db_name>"}]);
  • After setting up parse-server behind https, would it cause problems with parse-dashboard?

    • I have both server and dashboard running behind nginx reverse proxy with ssl. Working fine.

      • Do you use ParseFiles in your project? I am having an issue with downloading ParseFiles in my app. They upload fine and I can see them via the dashboard. But when it comes to downloading it gives me a “moved permanently” error. Which refers to the 301 redirect that Nginx is doing. Not sure how to fix this at all.

  • Is there a way to do this without “–sslAllowInvalidCertificates”? I believe if we can supply the correct CA file we should be able to actually validate the SSL cert, otherwise we are still vulnerable against man in the middle attacks. I have tried a few things but have not found a working solution yet.

  • Here is a video tutorial of existing app Parse Migration to Ubuntu at Digital Ocean folks !!!
    Hope you enjoy it !

  • Thank you for this tutorial ! Everything works fine for me, but I have an issue. I have always to use mydomainename/parse/parse to acess to my data. is there any way to fix that ?? and there will be any tutorial on how to add Parse-dashboard to point to the same domain name in the future ??


  • How to be able to migrate two Parse applications in the same server ??

  • Hi everybody,

    I’ve spent quite some time on it but finally figured out how to run parse-dashboard alongside the parse-server from this tutorial. Here are the steps:

    1. Set up parse-dashboard as a second express app in your index.js running on it’s own port (4040) and using /dashboard
    2. Change “script” value in ecosystem.json to your index.js path instead of parse-server: "script" : "/home/parse/index.js",
    3. Set up NGINX config to route /dashboard to http://localhost:4040/dashboard/ You can basically copy and change the location /parse/ config from step 4
    4. In you dashboard app setup the serverURL must be your public url like so: https://YOUR_DOMAIN/parse

    Hope this helps! ;-)

  • How is this:
    You will have to repeat the above command after renewing your Let’s Encrypt certificate. If you configure auto-renewal of the Let’s Encrypt certificate, remember to include this operation.
    actually done? I’ve set up ssl certificate and cron jobs for renewal according to this guide:
    I have tried to just add a cronjob in between :

    30 2 * * 1 /opt/letsencrypt/letsencrypt-auto renew >> /var/log/le-renew.log
    35 2 * * 1 /etc/init.d/nginx reload

    like so

    33 2 * * 1 cat /etc/letsencrypt/archive/{fullchain1.pem,privkey1.pem} | tee /etc/ssl/mongo.pem

    but this failed. after restarting my server mongod would’t start because of missing/unreadable mongo.pem

    Any ideas?

    by Mitchell Anicas
    In this tutorial, we will show you how to use Let's Encrypt to obtain a free SSL certificate and use it with Nginx on Ubuntu 14.04. We will also show you how to automatically renew your SSL certificate. If you're running a different web server, simply follow your web server's documentation to learn how to use the certificate with your setup.
  • Can you please advise on how to incorporate parse push using your method above? I’ve set up parse-server working well on a digital ocean droplet. Now need parse push to work, it’s the last bit in the parse app migration that I need.

  • I have followed this tutorial and everything was working fine, until I added ParseFiles to my application. The ParseFiles upload fine but after Upload I check the url of the parsefile like this,

    ParseFile file = new ParseFile("image.jpg", data);
            file.saveInBackground(new SaveCallback() {
                public void done(ParseException e) {
                    if (e == null) {
                        Log.d(tag, "Successfully uploaded image file to: " + file.getUrl());

    The url printed in the log says http and not https which is then causing a problem during the download. It tries to download from http and gets redirected via nginx with a 301. Which causes an exception in Parse-Android saying com.parse.ParseException: Download from S3 failed. Permanently moved. I have specified my url as https in the intialisation code and not sure why this is happening. Any help would be appreciated!

  • I followed this and the previous tutorial.

    I’m confused to whereas I should start the parse-server using “npm start” as mentioned in tutorial 1, or start using pm2 as mentioned in this tutorial.

    What’s the difference? And which one is the correct way to do it?

  • The complete Parse-Server and Parse-Dashboard Tutorials with DigitalOcean!

  • Hey, this tutorial used to work up until yesterday.

    Everything seems to be working fine, until Step 5. After adding nginx and setting up the ssl certificates I keep getting: curl: (35) Server aborted the SSL handshake when trying to run the curl command.

    Any ideas, what might be causing this?

  • Anyone have any ideas or pointers on getting parse-server to handle multiple apps?

    My initial thoughts are to house an instance of Mongo on one droplet that will contain all of my various app databases, and then on a second droplet install parse-server and create a new my_app.js style file for each app that I want to run?

    Or can I just define different api vars for each app maybe and name them after my app?


  • Hi, I am up to the part where we migrate the data from Parse, I get the success email from Parse, but when i try use mongo again from the terminal I get the following error:

    MongoDB shell version: 3.0.12
    connecting to: test
    2016-08-01T19:45:22.383-0400 I NETWORK  DBClientCursor::init call() failed
    2016-08-01T19:45:22.388-0400 E QUERY    Error: DBClientBase::findN: transport error: ns: admin.$cmd query: { whatsmyuri: 1 }
    at connect (src/mongo/shell/mongo.js:179:14)
    at (connect):1:6 at src/mongo/shell/mongo.js:179
    exception: connect failed

    I’m hoping that someone can help me out with my problem here, thanks.

  • I am getting this error when launching the Parse dashboard and my apps no longer work with Parse Server:

    error: Uncaught internal server error. { Error: connect ECONNREFUSED xx.xx.xx.xx:27017
    at Object.exports.errnoException (util.js:1036:11)
    at exports.
    exceptionWithHostPort (util.js:1059:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:14)
    name: ‘MongoError’,
    message: 'connect ECONNREFUSED xx.xx.xx.xx:27017’ } Error: connect ECONNREFUSED xx.xx.xx.xx:27017
    at Object.exports.errnoException (util.js:1036:11)
    at exports.
    exceptionWithHostPort (util.js:1059:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:14)

    Can somebody help me?

  • Thank you for the tutorial.
    I created an Ansible Repository by following the steps in this tutorial.
    You can easily migrate your app by running it as detailed in the README.
    Please check it, any feedback welcome!

  • Thank you for your article! I faced a problem while configuring mongod with ssl. Here’s what I got when I restart the service with SSL enabled:

    [main] No SSL certificate validation can be performed since no CA file has been provided; please specify an sslCAFile parameter

    As far as I understood I need to download another .pem from letsecrypt and point to it in mongo config. However I couldn’t do it properly after few attempts. As a side note: I use Ubuntu 16.04.1 for migration.

    Please help.


    After some trial and error I downloaded the intermediate certificate like this:

    sudo curl -o /etc/ssl/letsencrypt-ca.pem

    And then added the configuration property to SSL block:

      port: 27017
        mode: requireSSL
        PEMKeyFile: /etc/ssl/mongo.pem
        CAFile: /etc/ssl/letsencrypt-ca.pem
  • I am getting a 502 bad gateway error after I complete the last step, any help would be greatly appreciated!

Creative Commons License