How to setup your own Kadira instance on a VPS like DigitalOcean.

Sergio Tapia
sergiotapia
Published in
9 min readJun 22, 2017
Want your own Kadira? Read this guide!

Kadira is a great performance tracking application for Meteor apps.

Unfortunately it was recently shut down, but luckily it was open sourced for anyone to self-host.

In this guide I’ll show you from A to Z how to get Kadira running on a DigitalOcean droplet. It’ll take you around an hour to get everything up and running.

Many thanks to Michael Lazarski for his original guide. I used it as the foundation to this guide and expanded upon it.

https://medium.com/@foodfitnesscode/setting-up-kadira-on-a-ubuntu-16-04-server-part-1-a821cdddd1e6

Create your DigitalOcean droplet.

Pick Ubuntu 16.04 x64 for the OS. I created the 2GB ram droplet ($20/month), you can choose whatever fits your needs.

You can chose whichever droplet size fits your needs.

You’ll get your credentials via email. Login to your VPS and setup your initial password when prompted.

Heads up: I’m not a devops guys, I know enough to be dangerous and get the job done but that’s the limit. We’re going to use root for everything and this guide assumes that. If you use a specific “kadira” system account, this guide may not work out for you.

Let’s update our droplet to have everything we need installed.

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install ufw
sudo ufw allow OpenSSH
sudo ufw allow 543
sudo ufw allow 4000
sudo ufw allow 11011
sudo apt-get install nginx
sudo apt-get install git
sudo apt-get install nodejs
sudo apt-get install npm
sudo apt-get install python
curl https://install.meteor.com/ | sh

Installing MongoDB into our droplet.

These commands are all each one line, try to copy them over to a text editor first to format them properly.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6

Create the list file for MongoDB.

echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list

Reload your local packages.

sudo apt-get update

Install MongoDB.

sudo apt-get install -y mongodb-org

And finally run it.

sudo service mongod start

If everything was configured properly, you should be able to use the Mongo instance by using the mongo command.

root@hostname:~# mongo
MongoDB shell version v3.4.5
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.5

Kadira requires something special from Mongo in order to work. We need to configure replication sets.

sudo nano /etc/mongod.conf

Make sure you have this somewhere in that configuration file.

replication:
replSetName: "kadira"

Finally turn on replication for your Mongo instance.

mongo admin --eval 'rs.initiate({_id: "kadira", members:[{_id : 0, host : "localhost:27017"},]})'

And set it up as a slave.

mongo admin --eval 'rs.slaveOk()'

Create the necessary MongoDB collections.

Let’s create the collections Kadira needs from our Mongo instance. Each command is a single line.

mongouse kadiraApps
db.createUser({ user: "admin", pwd: "admin", roles: [ "readWrite", "dbAdmin" ]})
use kadiraData
db.createUser({ user: "admin", pwd: "admin", roles: [ "readWrite", "dbAdmin" ]})

Optimizing MongoDB for performance.

You can add some optimizations for our Mongo instance.

sudo nano /etc/init.d/disable-transparent-hugepages

Paste this in that file:

#!/bin/bash
### BEGIN INIT INFO
# Provides: disable-transparent-hugepages
# Required-Start: $local_fs
# Required-Stop:
# X-Start-Before: mongod mongodb-mms-automation-agent
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Disable Linux transparent huge pages
# Description: Disable Linux transparent huge pages, to improve
# database performance.
### END INIT INFO
case $1 in
start)
if [ -d /sys/kernel/mm/transparent_hugepage ]; then
thp_path=/sys/kernel/mm/transparent_hugepage
elif [ -d /sys/kernel/mm/redhat_transparent_hugepage ]; then
thp_path=/sys/kernel/mm/redhat_transparent_hugepage
else
return 0
fi
echo 'never' > ${thp_path}/enabled
echo 'never' > ${thp_path}/defrag
re='^[0-1]+$'
if [[ $(cat ${thp_path}/khugepaged/defrag) =~ $re ]]
then
# RHEL 7
echo 0 > ${thp_path}/khugepaged/defrag
else
# RHEL 6
echo 'no' > ${thp_path}/khugepaged/defrag
fi
unset re
unset thp_path
;;
esac

Make it executable.

sudo chmod 755 /etc/init.d/disable-transparent-hugepages

Enable it on boot.

sudo update-rc.d disable-transparent-hugepages defaults

Reboot the system and make sure you restart Mongo afterwards.

sudo reboot now

Setting up nginx for the project.

We already have nginx installed from a previous step earlier in this guide. Now we’re going to configure it. Basically we want two things to happen:

  • Port 80 routes internally to port 4000 for the kadira-ui project.
  • Port 11011 is routed to the kadira-engine project.

First let’s remove the default pages.

sudo rm /etc/nginx/sites-enabled/default

Create a new block for the kadira-ui project.

sudo nano /etc/nginx/sites-available/kadira

Paste this inside.

server_tokens off; # for security-by-obscurity: stop displaying nginx version# this section is needed to proxy web-socket connections
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# HTTP
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
# pass requests to Meteor
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; #for websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
# HTTPS server
server {
listen 443 default_server http2; # we enable SPDY here
server_name [::]:443 default_server; # this domain must match Common Name (CN) in the SSL certificate
root html; # irrelevant
index index.html; # irrelevant
# config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
add_header Strict-Transport-Security "max-age=31536000;";
# If your application is not compatible with IE <= 10, this will redirect visitors to a page advising a browser update
# This works because IE 11 does not present itself as MSIE anymore
if ($http_user_agent ~ "MSIE" ) {
return 303 https://browser-update.org/update.html;
}
# pass all requests to Meteor
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # allow websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP
# this setting allows the browser to cache the application in a way compatible with Meteor
# on every applicaiton update the name of CSS and JS file is different, so they can be cache infinitely (here: 30 days)
# the root path (/) MUST NOT be cached
if ($uri != '/') {
expires 30d;
}
}
}

Enable the new Kadira UI.

sudo ln -s /etc/nginx/sites-available/kadira /etc/nginx/sites-enabled/

Test to make sure the nginx configuration isn’t broken.

sudo nginx -t

Now we’re going to configure the kadira-engine block.

sudo nano /etc/nginx/sites-available/kadira-engine

Paste this in.

# this section is needed to proxy web-socket connections
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# HTTPS server
server {
listen 543 default_server http2; # we enable SPDY here
server_name [::]:543 default_server; # this domain must match Common Name (CN) in the SSL certificate
root html; # irrelevant
index index.html; # irrelevant
# config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
# to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
add_header Strict-Transport-Security "max-age=31536000;";
# If your application is not compatible with IE <= 10, this will redirect visitors to a page advising a browser update
# This works because IE 11 does not present itself as MSIE anymore
if ($http_user_agent ~ "MSIE" ) {
return 303 https://browser-update.org/update.html;
}
# pass all requests to Meteor
location / {
proxy_pass http://127.0.0.1:11011;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # allow websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP
# this setting allows the browser to cache the application in a way compatible with Meteor
# on every applicaiton update the name of CSS and JS file is different, so they can be cache infinitely (here: 30 days)
# the root path (/) MUST NOT be cached
if ($uri != '/') {
expires 30d;
}
}
}

Enable the kadira-engine block.

sudo ln -s /etc/nginx/sites-available/kadira-engine /etc/nginx/sites-enabled/

Test the nginx configuration.

sudo nginx -t

If everything went well you can now restart nginx!

sudo systemctl restart nginx

Cloning the open source Kadira project.

We’re going to clone the open source Kadira project onto our droplet and run it.

First let’s make sure we’re cloning it to the right place.

cd ~/
git clone https://github.com/lampe/kadira-server.git

Let’s dive into the kadira-server folder and edit the init-shell.sh file.

cd kadira-server/
chmod +x init-shell.sh
sudo nano init-shell.sh

Paste this in. Note that you’ll need to have your AWS credentials, and your droplet’s IP address for this file. Have those handy.

# DB settings export APP_MONGO_URL="mongodb://admin:admin@localhost:27017/kadiraApps"
export APP_MONGO_OPLOG_URL="mongodb://localhost:27017/local"
export DATA_MONGO_URL="mongodb://admin:admin@localhost:27017/kadiraData"
export MAIL_URL="smtp://postmaster%40kadira.io:9jx4fqhdfbg5@smtp.mailgun.org:587"
# Engine settings
export ENGINE_PORT=11011
export EXPORT_OPTIONS_URL="http://[YOUR DROPLET IP]:11011"
# UI settings
export UI_PORT=4000
export UI_URL="http://localhost:$UI_PORT"
# CPU Profiler needs a s3 bucket
export AWS_DEFAULT_REGION="eu-central-1"
export AWS_ACCESS_KEY_ID="[YOUR AWS ACCESS KEY]"
export AWS_SECRET_ACCESS_KEY="[YOUR AWS SECRET ACCESS KEY]"
# Monitoring Setup
export LIBRATO_EMAIL
export LIBRATO_TOKEN

At this point we’re just about finished. Now we need to go through each microservice Kadira has and set it up as a managed service and we’re all set.

Let’s wrap this up!

Kadira Engine

cd ~/kadira-server/kadira-engine
npm install
source ../init-shell.sh
chmod +x run.sh

Run it manually to see if everything is work as expected.

./run.sh

Create a service for kadira-engine.

sudo nano /etc/systemd/system/kadira-engine.service

Paste this in.

[Unit]
Description=kadira-engine
[Service]
Type=simple
User=root
WorkingDirectory=/root/kadira-server
ExecStart=/bin/bash -c "source /root/kadira-server/init-shell.sh; cd /root/kadira-server/kadira-engine; ./run.sh"
Restart=on-abort
[Install]
WantedBy=multi-user.target

Start the service.

systemctl start kadira-engine.service

Check it’s status.

systemctl status kadira-engine.service

Finally enable it.

systemctl enable kadira-engine.service

Kadira RMA

We need to create a new records in our Mongo instance for Kadira RMA to work properly.

mongo
use kadiraData
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'1min',provider:'methods',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'1min',provider:'errors',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'1min',provider:'pubsub',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'1min',provider:'system',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'3hour',provider:'methods',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'3hour',provider:'errors',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'3hour',provider:'pubsub',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'3hour',provider:'system',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'30min',provider:'methods',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'30min',provider:'errors',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'30min',provider:'pubsub',shard:"one"}})
db.mapReduceProfileConfig.insert({lastTime: new Date(), _id:{profile:'30min',provider:'system',shard:"one"}})

Now let’s setup the project.

cd ~/kadira-server/kadira-rma
npm install
source ../init-shell.sh
chmod +x run.sh

Run it manually to see if everything is work as expected.

./run.sh

Create a service for kadira-rma.

sudo nano /etc/systemd/system/kadira-rma.service

Paste this in.

[Unit]
Description=kadira-rma
[Service]
Type=simple
User=root
WorkingDirectory=/root/kadira-server
ExecStart=/bin/bash -c "source /root/kadira-server/init-shell.sh; cd /root/kadira-server/kadira-rma; ./run.sh"
Restart=on-abort
[Install]
WantedBy=multi-user.target

Start the service.

systemctl start kadira-rma.service

Check it’s status.

systemctl status kadira-rma.service

Finally enable it.

systemctl enable kadira-rma.service

Kadira UI

We need to configure a few extra files for this project.

Start by editing the settings.json file.

cd ~/kadira-server/kadira-ui
sudo nano settings.json

Then make sure the file contents look like this:

{
"public": {
"tender": {
"key": "405871e6-4816-4d44-a0f3-860c0e988078"
},
"s3Url": "https://[YOUR BUCKET NAME HERE].s3.[YOUR BUCKET REGION HERE].amazonaws.com/",
"intercom": {},
"loginState": {
"domain": "",
"cookieName": "kadira-dev-login-state"
}
},
"tender": {
"secret": "71825e70-d11d-489b-b273-2afdca024fd6"
},
"stripe": {
"kadirahq": {
"apiKey": "sk_test_22QITCBPhqEaEKjHXK5BBwO8",
"publishableKey": "pk_test_Tc1iVNRP9p8o7zgYWoWjZnm4",
"appName": "KadiraHQ",
"appLogo": "https://kadira.io/favicon.ico"
}
},
"meteorDevelopers": {
"clientId": "HcempmSyaawiyb4G4",
"secret": "snC3snsmTebC8HHCwwhqhHaAzAFxtFsQRL"
}
}

Then edit run.sh to allow for superuser functionality since we’re running everything using the root user.

#!/bin/bashMONGO_URL=$APP_MONGO_URL \
MONGO_OPLOG_URL=$APP_MONGO_OPLOG_URL \
MONGO_SHARD_URL_one=$DATA_MONGO_URL \
MAIL_URL=$MAIL_URL \
ROOT_URL=$UI_ROOT_URL \
meteor --allow-superuser --port $UI_PORT --settings ./settings.json $@

Let’s install the dependencies now.

npm install
source ../init-shell.sh
chmod +x run.sh

Run it manually to see if everything is work as expected.

./run.sh

Create a service for kadira-ui.

sudo nano /etc/systemd/system/kadira-ui.service

Paste this in.

[Unit]
Description=kadira-ui
[Service]
Type=simple
User=root
WorkingDirectory=/root/kadira-server
ExecStart=/bin/bash -c "source /root/kadira-server/init-shell.sh; cd /root/kadira-server/kadira-ui; ./run.sh"
Restart=on-abort
[Install]
WantedBy=multi-user.target

Start the service.

systemctl start kadira-ui.service

Check it’s status.

systemctl status kadira-ui.service

Finally enable it.

systemctl enable kadira-ui.service

Kadira API

cd ~/kadira-server/kadira-api
npm install

Create a service for kadira-api.

sudo nano /etc/systemd/system/kadira-api.service

Paste this in.

[Unit]
Description=kadira-api
[Service]
Type=simple
User=root
WorkingDirectory=/root/kadira-server
ExecStart=/bin/bash -c "source /root/kadira-server/init-shell.sh; cd /root/kadira-server/kadira-api; ./run.sh"
Restart=on-abort
[Install]
WantedBy=multi-user.target

Start the service.

systemctl start kadira-api.service

Check it’s status.

systemctl status kadira-api.service

Finally enable it.

systemctl enable kadira-api.service

Kadira Alertsman

cd ~/kadira-server/kadira-alertsman
npm install

Create a service for kadira-api.

sudo nano /etc/systemd/system/kadira-alertsman.service

Paste this in.

[Unit]
Description=kadira-alertsman
[Service]
Type=simple
User=root
WorkingDirectory=/root/kadira-server
ExecStart=/bin/bash -c "source /root/kadira-server/init-shell.sh; cd /root/kadira-server/kadira-alertsman; ./run.sh"
Restart=on-abort
[Install]
WantedBy=multi-user.target

Start the service.

systemctl start kadira-alertsman.service

Check it’s status.

systemctl status kadira-alertsman.service

Finally enable it.

systemctl enable kadira-alertsman.service

We’re done with project setup!

Now you need to create an account so you can use the Kadira app in the browser. The easiest way is to add the code to automatically create an account.

sudo nano ~/kadira-server/kadira-ui/server/methods/account.js

Paste this in somewhere in the file.

Meteor.startup(() =>{
Accounts.createUser({
username: 'someusername',
email: 'test@email.com',
password: "somepassword"
})
})

Reload the page a few times: http://your-ip-address:4000

Then go back to edit the same file and remove that code you just added. It’s no longer needed.

Try logging into your account now you should be able to sign in and create a project to get your Kadira keys.

Hooking up your Meteor project to your personal Kadira instance.

This is it! You made it this far, get ready for some sweet performance analytics!

In your settings.json file, make sure you have a Kadira option.

"kadira": {
"appId": "[your-app-id]",
"appSecret": "[your-app-secret]",
"options": {
"endpoint": "http://[your-ip-address]:11011"
}
}

Run your Meteor project using the settings flag.

meteor run --settings settings.json

And you’re done!

I hope you enjoyed this guide and it helped you save some time. Leave a ❤️ if you liked it, thanks!

--

--