Best of breed version of mup(x)?

Today, my mupx-based build process broke, becaue I updated my Node.js installation to version 6. I guess it is due to this issue:
https://github.com/arunoda/meteor-up/issues/1001

Now I read there that mupx is (long) deprecated and one should use mup kadirahq/meteor-up instead. For a long time I avoided this, because it was still marked as being under development. Now I see that this note has been removed.

So my question to the community: Who has experiences with moving from mupx to kadirahq/meteor-up. Was the transition smooth, or should I expect major trouble and rather downgrade my Node.js instead?

I know that the whole mup(x) ecosystem might be somewhat deprecated now, but I need a quick fix before I have time to investigate in other options. Just have to update my server now.

So any advice on the “best of breed” version of mup(x) is highly appreciated. I was always quite puzzled by the high number of mup’s out there.

1 Like

Does Meteor work with Node version 6 (regardless of deployment method)?

I just transitioned a bunch of apps from mupx to pm2-meteor because I was sick of pinning apps to Meteor 1.2, just so they’d deploy with mupx. Transitioning to pm2-meteor was pretty painless (config files are similar to those of mupx) and everything “just worked”, which was great. So now my one-liner deploy command is pm2-meteor deploy instead of mupx deploy. The six extra characters was worth it to be able to use the latest version of Meteor with confidence.

1 Like

No, but I had installed it globally and mupx used it for building (dunno why).

Cool. Is it really that easy? Does it support SSL (could not find info about this on the npm page)?

Well … to be fair … pm2-meteor has a

mupx deploy

equivalent (i.e. pm2-meteor deploy), but not the equivalent of

mupx setup

so there is some initial setup to do on the server, which would include setting up SSL termination using nginx or something like that. This is easy enough to do once you’ve done it once or twice before (and if you know what goes in the nginx.conf file). I can share what I’ve done to get SSL working if you like.

1 Like

That would be awesome! Thanks.

Okay. The hardest part is getting the right files from the certificate provider and knowing which is which. I’m assuming you’ve got a SSL certificate (for guzz.io) and so you have three files available that correspond to:

ssl.pem
ssl.key
trusted.pem

If you have those right, the rest should be easy enough.

By way of reference, ssl.pem should have:

-----BEGIN CERTIFICATE-----
<LOTS OF RANDOM LETTERS AND NUMBERS>
-----END CERTIFICATE-----

with possibly one or two of these in the middle of the random letters and numbers:

-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----

(i.e. it might be several certificates concatenated together)

trusted.pem should be similar, but just a single certificate, i.e.:

-----BEGIN CERTIFICATE-----
<LOTS OF RANDOM LETTERS AND NUMBERS>
-----END CERTIFICATE-----

ssl.key should be something like this:

-----BEGIN PRIVATE KEY-----
<LOTS OF RANDOM LETTERS AND NUMBERS>
-----END PRIVATE KEY-----

Now, here are the commands to issue on the (Ubuntu 16) server as a user with sudo privileges:

1. Installing nginx

sudo apt-get update
sudo apt-get install nginx

And, if /var/log/nginx is not already a directory:

sudo mkdir /var/log/nginx

2. Puttting the certificates in the right place

sudo mkdir /etc/nginx/ssl/guzz

Now we need to get the certificate and key files (listed above) onto the server in the /etc/nginx/ssl/guzz directory we’ve just created. For simplicity’s sake, you can get the text of the .pem and .key files (open them in a text editor) and copy and paste it into files you create by issuing each of these commands:

sudo pico /etc/nginx/ssl/guzz/ssl.pem
sudo pico /etc/nginx/ssl/guzz/ssl.key
sudo pico /etc/nginx/ssl/guzz/trusted.pem

(Not sure if you’ve used the pico text editor before. It’s CTRL+X then Y then ENTER to save changes.)

3. The nginx config file

Now we need an nginx config file that supports SSL for your app in the /etc/nginx/sites-available directory:

sudo pico /etc/nginx/sites-available/guzz.io

Paste this in to the new file we’ve just created/opened for editing:

upstream node_server {
   server 127.0.0.1:3000 fail_timeout=0;
   # if you need multiple instances of the app running on the same server (e.g. if you have multiple server cores available):
   # server 127.0.0.1:3001 fail_timeout=0;
   # server 127.0.0.1:3002 fail_timeout=0;
   # server 127.0.0.1:3003 fail_timeout=0;
}

server {
  listen         80;
  server_name    guzz.io;
  return         301 https://$server_name$request_uri;
}

server {
  listen         443 ssl;
  server_name    guzz.io;  

  access_log            /var/log/nginx/app.access.log;
  error_log             /var/log/nginx/app.error.log;

  ssl_certificate           /etc/nginx/ssl/guzz/ssl.pem;
  ssl_certificate_key       /etc/nginx/ssl/guzz/ssl.key;
  ssl_trusted_certificate   /etc/nginx/ssl/guzz/trusted.pem;
  ssl_session_cache shared:SSL:20m;
  ssl_session_timeout 10m;
  ssl_prefer_server_ciphers       on;
  ssl_protocols                   TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers                     ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;

  add_header Strict-Transport-Security "max-age=31536000";

  location / {
    proxy_pass http://node_server;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

I won’t go into the details of all the parts of the nginx config file (partly because I’m a bit shaky on some of the finer details), but basically the upstream node_server block tells nginx which port(s) your app instance(s) is(are) running on, and the server blocks are telling nginx which ports requests from the internet will be coming from.

Notice that traffic on port 80 (the http port) is redirected to port 443 (the https port) and it’s that server block that has all the SSL cert stuff, along with the location block (which ensures we get sticky sessions).

Now we need this nginx config file represented in /etc/nginx/sites-enabled, so we symlink to the file with this command:

sudo ln –s /etc/nginx/sites-available/guzz.io /etc/nginx/sites-enabled

Remove the default nginx config from /etc/nginx/sites-enabled:

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

4. Starting nginx:

Let nginx traffic through the firewall, if it has been set up:

sudo ufw allow 'Nginx Full'

Then start nginx:

sudo systemctl start nginx

Hopefully, you now have SSL termination courtesy of nginx and can pm2-meteor deploy new versions of your app (make sure the pm2-meteor config file has port: 3000 set, as that’s the port where nginx expects there to be a running app instance).

1 Like

Wow, thanks a lot for this detailed description, highly appreciated!

Yes, I already have SSL certificates and am aware about how to create them. In fact, I am using letsencrypt for www.guzz.io, and it works like a charm. I guess with “trusted.pem” you mean the certificate chain? With mupx I used the fullchain.pem instead, which included the certificated and the chain. But I have the separate files, too, so I will try it as you described. Again, thanks a lot for this writeup!

If you’ve already got a fullchain.pem you might get away with using that for ssl.pem and removing this line from the nginx config file:

ssl_trusted_certificate   /etc/nginx/ssl/guzz/trusted.pem;

I’m pretty ignorant about how certificates are handled and why you have to concatenate them, what order to concatenate them, etc.

1 Like

Thanks!

So am I. It’s always a bit of trial and error :slight_smile:

1 Like

Hi, I switched from mup to kubernetes with Docker and never looked back. It was a bit of a process, but well worth it. The basic steps are:

  1. Dockerize the app (use meteor build and a node image instead of MeteorD). I based my node image on this one. I versioned my docker images with this code so they would be human readable and unique:
# build locally
rm -rf $BUILDDIR
(cd $APP && \
  meteor build \
  --directory ../$BUILDDIR \
  --architecture os.linux.x86_64 \
  --server-only) || exit

# docker it
VERSION=$(node -p -e "require('./package.json').version")-$(git rev-parse --short HEAD)
tar -cz Dockerfile package.json -C $BUILDDIR bundle | \
  docker build -t $REPO:$VERSION - || exit
docker push $REPO:$VERSION
  1. Deploy a Kubernetes cluster (Google Cloud is cheaper than AWS)

  2. Copy environment and settings.json into a secret. Connect those secrets as a volume, then run a script from your docker image to load them. E.g. before running your app this script:

if [ -f "/etc/env-volume/env.sh" ];  then
  echo "Environment volume found"
  source /etc/env-volume/env.sh
else
  echo "WARNING: Environment volume not found"
fi
npm ${1:-start} 
  1. Use the nginx ingress controller, not the native ones for AWS/GCloud.
4 Likes

That’s great info, Michael. Do you think you could write a more detailed blog post for the less familiarized with kubernets, nginx, gcloud…?

I’d really appreciate that!

1 Like

Hi @Ifilho, I started to, but damn it’s alot of material. I’ve got a side project lined up to cover it, but it will take a couple months to get started on.

What I learned:

  • For the money, Galaxy/Modulus is the best for single server setups. Also best for easily turning projects over to short-term clients.
  • I needed to install a custom binary, so digitalocean+mupx+bash worked for a time, but no more.
  • Kubernetes is cool, and alot simpler than it looks. I spent ~40 hrs building my current setup over 2 weeks (once on AWS, then on GCE), and twice that on bash+mupx
  • I a 3rd party mongodb service to make it simpler.

Good luck! I’ll link back here if I get the project up :slight_smile:

1 Like

I have been running Meteor 1.3.x using mupx to deploy for the last year or so, and have been very happy with it.

Recently, we decided to enable HTTPS encryption, which mupx supports through some additional mup.json settings. However, we wanted to automate the renewal of our LetsEncrypt certs, which mupx does not do out of the box.

Through some forum posts I found this fork of mupx: mupx-letsencrypt, which automatically generates and renews LetsEncrypt certs for your server. FYI, LetsEncrypt certificates default to a 90 day expiration date, so automated renewal is useful to keep them current.

So far, it has been easy to use and appears to work perfectly. There is also a version of mupx-letsencrypt for Meteor 1.4.x, but I have not tested it.

Hope that is useful feedback about mupx.

Thanks for that info! I would definitely love to use a mupx version that auto-renews letsencrypt certs. And if this is also available for 1.4, changes are good that it also supports newer Node versions. Would be awesome. I’m still on Meteor 1.2, though, hope they support it, too.