Setting up Meteor 1.4+, Meteor Up, LetsEncrypt SSL, and Nginx in 15 minutes

Probably the simplest way to deploy a single instance of Meteor. Once you’ve done this once it takes about 15 minutes to set up a new deployment.

Install and set up kadirahq/meteor-up. We’ll be setting up mup to allow for multiple environments, if you want to deploy a develop, release, master, etc. You can find a sample mup.js on kadirahq/meteor-up. You’ll want to deploy to port 3000 or some other not 80 port since we’re going to use Nginx as a reverse proxy. Also note to use abernix/meteord:base as your docker image if you’re using Meteor 1.4+. It’s not good practice to check your mup file into VCS, it will contain your deployment user’s password.

# in the root of your meteor project
sudo npm install -g mup
mkdir .mup
touch .mup/my_deployment.mup.js
touch .mup/my_deployment.settings.json
# fill out your mup.js and settings.json files, we'll use meteorapp as our deployment user

Set up an Ubuntu 16.x virtual machine in your favorite host. Create a meteorapp account that we’ll use for deployments. Be sure to choose a sufficiently strong password for the account.

sudo apt update
sudo adduser meteorapp
sudo adduser meteorapp sudo

Update the /etc/sudoers file to allow password-less sudo for mup.

sudo nano /etc/sudoers
# add this line to before "# See sudoers(5) for more information on "#include" directives:"

Install Nginx and LetsEncrypt.

sudo apt install nginx
sudo service nginx stop
sudo apt install letsencrypt

Generate a LetsEncrypt certificate for your domain. Add it to the Nginx config.

sudo letsencrypt certonly -d my_domain.tld
sudo nano /etc/nginx/sites-enabled/default
# add the following information to the top to rewrite http to https
server_tokens off;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
server {
listen 80;
rewrite ^(.*) https://$host$1 permanent;
# add this block for each Meteor instance you'll run on the vm, be sure to update the domain (and the port if you're not using 3000)

server {
server_name my_domain.tld www.my_domain.tld;
listen 443;
ssl on;
ssl_certificate /etc/letsencrypt/live/my_domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/my_domain.tld/privkey.pem;
# performance enhancement for SSL
ssl_stapling on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 5m;
# safety enhancement to SSL: make sure we actually use a safe cipher
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# config to enable HSTS(HTTP Strict Transport Security)$
# to avoid ssl stripping$
add_header Strict-Transport-Security "max-age=31536000;";
# If your application is not compatible with IE <= 10, this will redirect vi$
# This works because IE 11 does not present itself as MSIE anymore
if ($http_user_agent ~ "MSIE" ) {
return 303;
location / {
proxy_pass http://localhost:3000;
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

Add a crontab entry to automatically renew your cert.

sudo crontab -e
# add the crontab line
30 2 * * 0 service nginx stop && /usr/bin/letsencrypt renew >> /var/log/le-renew.log && service nginx start # renew if required at 2:30 am on Mondays

Using the newer certbot? You can just call:

0 2 * * * certbot renew --pre-hook "service nginx stop" --post-hook "service nginx start"

Start Nginx back up again.

sudo service nginx start

Set up and deploy your Meteor app on your local machine.

mup setup --config .mup/my_deployment.mup.js --settings .mup/my_deployment.settings.json
mup deploy --config .mup/my_deployment.mup.js --settings .mup/my_deployment.settings.json
mup deploy --config

Sidenote: Getting mup failures on the Verifying Deployment step? Try bumping deployCheckWaitTime to 120 in your mup.js file.

You’re done!

Next steps? Set up continuous deployment by triggering mup deploy on a push to your VCS.