Installing CouchDB on Google Compute Engine

Posted: 04 December, 2018 Category: code Tagged: gcpcompute enginenosqlPWA

I want to use the auto-syncing magic of CouchDB to finish building my PWA app. This necessitates PouchDB on the frontend. I’ll wire that in later, but first, I’d like my CouchDB instance to live in the sky, and I’m skint, so "No" to CouchBase for now. That leaves rolling my own. Now according to GCP, I can have a compute instance for free(-ish):

supposedly free stuff

And then there’s this install guide, So here goes nothing. Yikes!

** DISCLAIMER - this is the masochistic route: you can totes spin up a Bitnami couchdb config'd VM on GCP and (supposedly) just get on with your life, but this is the slow road to maximise learning about compute and GCP in general. I also for some reason thought the Bitnami one would cost more - not sure that it does. **

1. Create a Compute Engine Instance

Go to your GCP console > Compute Engine and click to create a new instance!

  • CPU : f1-micro (vcpu with 0.6Mb ram (!!!) 10G disk). Hey - we're keeping it cheap and tiny.
  • OS : Debian Gnu-Linux 9 (stretch)
  • Compute Engine default service account
  • Full access to all cloud apis (why? uhm... i dunno in case I wanna play with other stuff later)
  • Allow http, https traffic (for now, mostly dev) It’s getting created! instance being created

Once it's up, your instance should be assigned an external IP address and you should be able to ping it.

2. Connect to the Instance

You can connect directly in-browser - just use the ssh menu on the instance: connect via ssh

Decided to forego enabling OS login for now which seems to be the opposite of the ssh-enabled logins? Not fully comprehending.

Btw: The cloud SDK command for ssh'ing from your local commandline is: cloud compute --project pid ssh --zone "us-east1-b" instance where pid is your gcp project ID and instance is the name of your new compute engine instance. Substitue other things like zone as needed. I wasn't using the cloud SDK at this time.

A wee bit of housekeeping:

  • CHANGE THE ROOT PASSWORD: sudo passwd
  • Update packages! sudo apt update && sudo apt upgrade -y

3. (Optional detour): Install Node

I followed the outline here: https://cloud.google.com/nodejs/docs/setup

First, you install nvm:

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash

close your gcp ssh terminal and reopen. Then:

nvm install stable

That's it! node is installed and the last stable version has been made your default node version.

4. (Optional detour): Run a Server

Kicking off a tiny server just to illustrate... e.g. index.js:

const http = require('http')
const port = 80
const requestHandler = (request, response) => {
  console.log(request.url)
  response.end('Hello from compute Engine!!')
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
  if (err) {
    return console.log('oops', err)
  }
  console.log(`server is listening on ${port}`)
})

and then just run it with node index.js just to see if you can hit up your server external ip in a browser.

Didn't work, eh? Hehe. That's what happened to me too. The port # is too low/restricted, and I'm not root. Fixed this by giving the nodejs executable the CAP_NET_BIND_SERVICE capability (see things I learned, bottom of page):

sudo apt-get install libcap2-bin
sudo setcap cap_net_bind_service=+ep `readlink -f \`which node\``

Starting the server this time worked and I could hit the machine from my browser! Whoo!! What does this prove? Not a lot. I told you this was an optional detour. Onwards:

5. Install CouchDB Binaries

Because what I won't do, is install this thing from source. So I'm following this guide instead. Follow instructions for your flavor of 'nix. Everything that follows is for Debian 9:

$ echo "deb https://apache.bintray.com/couchdb-deb stretch main" | sudo tee -a /etc/apt/sources.list

$ curl -L https://couchdb.apache.org/repo/bintray-pubkey.asc | sudo apt-key add -
$ sudo apt-get update && sudo apt-get install couchdb

Gah! "E: The method driver /usr/lib/apt/methods/https could not be found."

Fix: sudo apt-get install apt-transport-https and rerun the above command; worked. Finally saw the install screen:

connect via ssh

Hereof:

  • Install as default (standalone)
  • 127.0.0.1 loopback IP (for now - changed later in step 8)
  • Then added an admin password when prompted. Done!

ps -ef | grep couchdb at this point will show that couchdb is actually running.

6. Add a Couchdb User to the machine

Referred to this doc, which said to run adduser --system --shell /bin/bash --group --gecos "CouchDB Administrator" couchdb. But it "couldn't find adduser". Trying as sudo worked, but then it said user 'couchdb' already existed. Wha...?? This part was confusing... The command id couchdb revealed that it was indeed a system user. su - couchdb asked for a password and I tried using the one I thought I'd created earlier. Natch, it didn't work, cos that password was for a DB admin, NOT a system user. But, brain fartz. Panicking, I did this foolish thing:

# DON'T DO THIS
sudo -
passwd couchdb
# (force set pwd to the db admin pwd. BAD!)
logout
su - couchdb
# (enter the pwd... we're in!!)

It was only until step 9 I realized how completely barmy I'd gotten at this point.

Moving on swiftly: echo $HOME reveals this user's home directory as /opt/couchdb. So the lines:

As a recommendation, copy the rel/couchdb directory into /home/couchdb or /Users/couchdb

...and in fact all the following lines in that section of the install guide made precious little sense. So I'm just going to run with the assumption that the documentation simply hasn't caught up to reality, and everything couchdb needs is ACTUALLY already nested in /opt/couchdb/*/*... and I mean, the perms look about right, don't they?

files in /opt/couchdb

7. Add Firewall Rule for CouchDB

Click on the name of your compute instance in your gcp console. Click on the name of the network interface and/or navigate to VPC network > Firewall Rules. I created something basic and rather permissive for couchdb traffic: Ingress firewall rule

8. Bind to the external port of the machine

The point is to be able to reach this db from my local machine, so I edit the [chttpd] block in CouchDB's config file. The config file lives at /opt/couchdb/etc/local.ini, and the edits amount to:

[chttpd]
port = 5984
bind_address = 0.0.0.0

Then restart couchdb: sudo service couchdb restart.

9. Try to hit the DB!!

So to get to the management console (named "Fauxton"), you hit the url with the format external-ip:port/_util/. Where 'external-ip' is the external IP of your compute instance, and the port # will normally be 5984 for couchdb (as configured in steps 7 and 8). Go that url, and then this is what you see!

db login page

When I tell you I swore a blue streak when I saw that screen! :)

And I was able to log in with the admin db password I'd created way back at the end of step 5! Whooo!!

logged in

I hope these steps help somebody out there!


Things I learned:

  • Besides manually creating a vm like this, you can actually programmatically do the same thing. On hindsight, and for future, I will likely go this route - if only because the scripts run as root, making things like spinning up servers on restricted ports much more smooth-sailing (for the sake of hitting the ground running. Obvs better keep restricted ports restricted). To programmatically spin up a vm, here are some resources to guide you:

  • The root password is actually NOT SET on a compute instance.. you need to set it on first login:

    sudo passwd
    # (enter new pwd)
    # (confirm new pwd)
  • Was good to refresh my memory on some linux cmds:

    • cat passwd shows you all the users on a system
    • su - login as root
    • su - someuser login as some user
    • passwd someuser reset someone's password (as root)
  • I learned that Non-Root Port Binding is a thing, and it's a thing one needs to workaround. The general strategies seem to be, in order of preference:

    1. give root permission (eg create user that can run as root, and have your program run as that user)... but as soon as you've bound to the port, drop root privileges. The application itself has to do this, in the code. Noone seemed to have anything to bad to say abt this approach.
    2. forward from restricted ports to ports higher than 1024. Though, I read an SO answer that says this yields wasteful copy-paste activity with buffers. Shrug.
    3. Use the CAP_NET_BIND_SERVICE capability: let programs have root privs, but only for socket traffic on the restricted port(s). Note: Anything given this capability can therefore listen on any port, albeit in this restricted way. Some might argue that's not all that secure. There are some more caveats In the top answer listed on this SO thread.
    4. Just throw your hands up in the air and use a higher port number like you just don't care.

    I went for option 3. Because it is the dev-friendliest approach.

  • Been a while since I played with gcp: learned the command to update my cloud sdk: gcloud components update, even though I didn't really use them this time round. But you should, if you're going to try to build VMs via script.

  • Connecting to Instances: Basically, if you have:

    • installed the cloud SDK and are using it on the commandline, or
    • are connecting directly to your instance via SSH in-browser, or
    • are using the google cloud shell (also in-browser)...

    ...then all your SSH certs handled for you by the above tools.