form.io install without Docker

The form.io documentation on how to get things working is a little vague. It mostly refers to the Docker container, which I don’t like using, you never know what’s in there or what has been done that you might not like. Although, we’re running code straight off the internet anyway, so if people wanted to be injecting “bad stuff” they could probably find other places to do it.

Instance and Pre-requisites

This walk-through is based on Amazon Linux. It will likely work on many RHEL-like Linux as well. If you’re running recent versions, you’ll need to change things like chkconfig and service commands for systemctl. Covering all possible OSs is beyond the scope of this one document!

Start with an Amazon Linux instance. You may need a public IP address and DNS name if you want this system to be publicly usable. NB use an EIP on AWS.

I like to keep apps&data off the root partition where possible. So added an extra 8GB partition (/dev/xvdb) I mounted as /data. If you’re happy with mongo data being in /var/lib/mongo (on the root filesystem) then make your own adjustments.

Run the following as root :

mkfs.ext4 /dev/xvdb
mkdir /data
mount /dev/xvdb /data
tail -1 /etc/mtab >> /etc/fstab
 
 
cat > /etc/yum.repos.d/mongodb-org-3.6.repo << EOF
[mongodb-org-3.6]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.6/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc
EOF
 
 
yum -y install nginx mongodb-org
chkconfig nginx on
chkconfig mongod on
 
sed -ibak '/dbPath:/s+/var/lib+/data+' /etc/mongod.conf
 
 
service mongod start

If you want to get more perfomance, then you might want the XFS filesystem :
https://scalegrid.io/blog/xfs-vs-ext4-comparing-mongodb-performance-on-aws-ec2/

However, you don’t need it. And there are likely other things to improve performance that I’m not even aware of.

Secure mongo

I have a history with insecure mongo databases. (Don’t ask!). This is an absolute minimum, you may also want to encrypt connections and more, especially if you are talking to a remote mongo server. For a production system, you would likely want HA and multiple clustered mongo nodes (Remote mongo and clusters are beyond the scope of this doc!).

You are currently running an insecure mongo, but it is only listening on 127.0.0.1. So nobody not on your instance may connect. Now is the time to fix this, from the mongo shell (type: mongo)

use admin
db.createUser( { user: "admin", pwd: "admin.password",roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] })
 
use formioapp
db.createUser({user: "formio", pwd: "form.password", roles: [ {role: "readWrite", db: "formioapp"}] } )

You’ve created the users with passwords, but people may still connect to your DB without them. You need to tell the server process to require authentication :

service mongod stop
cat >> /etc/mongod.conf << EOF
security:
 authorization: enabled
EOF
service mongod start
 
 
#Test it!
mongod
> show dbs
# Should fail!
mongo -u admin -p admin.password --authenticationDatabase admin
> show dbs
# Should work!
# Validate mongo listening only on localhost too:
ss -anp | grep mongo

 

nginx config

We use nginx as a simple proxy to connect to the npm port. npm runs on port 3001. IF you install an application into your form.io system, then it may run on port 8080. You will need to figure the config for that out for yourself I’m afraid. You need an ssl key/cert. You can probably use self signed for now or letsencrypt (getting SSL setup is beyond the scope of this doc). Create /etc/nginx/conf.d/formio.conf, with this content:

# Redirect port 80 to 443 :
server { server_name formio.company.com; listen 80; location / { return 301 https://$server_name$request_uri; } }
 
# Create an SSL server
server {
 listen 443 ssl;
 server_name formio.company.com;
 ssl_certificate /etc/pki/tls/certs/formio.company.com.crt;
 ssl_certificate_key /etc/pki/tls/private/formio.company.com.key;

 
 
 
# NGINX usually only allows 1M per request. Increase this to maximum attachment size 
 client_max_body_size 10M;
 
 location / {
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-Host $host;
 proxy_set_header X-Forwarded-Proto https;
 proxy_set_header X-Forwarded-Server $host;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_pass http://localhost:3001/;
 }
}

I don’t think you need all the proxy_set_headers, just the proxy_pass. “location /formio/” could be added if you want it to run formio in a subfolder of a site.

After that, start nginx :

chkconfig nginx on
service nginx start

form.io itself

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
 
nvm install 8
cd /data
git clone https://github.com/formio/formio.git
cd formio/
npm install

Before you start it, and that will take you through the configuration steps, you need to set some things up. Like the security for the mongo DB and the actual servername you are running this from. In /data/formio/config/default.json change it to look like this :

 "appPort": 8080,
 "host": "localhost:3001",
 "protocol": "http",
 "domain": "https://formio.company.com/",
 "basePath": "/",
 "mongo": "mongodb://formio:form.password@localhost:27017/formioapp",
 "mongoSecret": "secret",

IF you want to serve it from a subfolder, add the formio/ to the end of the domain and basepath values.

The mongoSecret is a database encryption key. A bit further down your will see a jwt.secret as well.
You should set them to something else. Ideally a long random string. I couldn’t find any advice from form.io on how long a string to use, so this is guesswork but probably over 80 bits of entropy.

You should now be able to do an “npm start” command and configure the form.io install. I normally accept all the defaults and supply an email address and complex password.

I leave it as an exercise to the reader to install some sort of startup script. forever or pm2 might be useful.

Debugging

My first suggestion here is to install tcpdump. Then tcpdump on your loopback interface and port 3001 with 0 snaplength and “ASCII” mode.

tcpdump -Ans0 -i lo port 3001

That will show you requests coming in to your form.io install. You can also replace the loopback interface with your external interface (en0 maybe?) and port 3001 with port 443. That will show encrypted traffic, not very useful. To debug at that side, you would need to change the nginx config to serve unencrypted over port 80 and tcpdump there.

Site fails to load at all

When you browse to your site if it fails to load anything and you get either a 404 error or some other failure but no form.io looking page :

  • Check nginx access logs. See if you are even getting to your server. Check firewalls, DNS, etc…
  • If you see nginx logs, look at the tcpdump above if you see nothing at all in tcpdump, check your nginx config.

Something loads but it doesn’t work

If you use a subfolder to serve formio, requests should not have any subfolder in the GET to the formio server.
eg if you browse to https://formio.company.com/formio the tcpdump should show GET /

Check the HTML/js you get from your server includes links to your server and not to localhost:3001. If it says it can’t contact the api server, then you’ve probably failed to configure the default.json correctly. Stop npm, fix the default.json, delete the “client” subdirectory and restart npm. You will need to reconfigure the basic settings again.