Introduction
Meteor enables developers to create apps and quickly test them on a development webserver. Once you have created your app the big question is how to run it on a production server. In this tutorial we will demostrate how to run your Meteor app on Ubuntu 16.04 using NginxCredits and Acknowledgements
This entire post is based off this Digital Ocean article. The article was modified for issues we encountered and adapted for Ubuntu 16.04. The entire credit goes to Daniel SpeichertObjective
In this tutorial we will:- Install and Configure Nginx with HTTPS enabled
- Install MongoDB
- Install NodeJS
- Bundle your Meteor App
- Create a startup script to automatically start your app on reboot
Assumptions
We assumue the following:- You already have a fresh install of Ubuntu 16.04 Server
- SSH enabled on your fresh install
- You have root privelages on your server
- You have a different server where you can insall meteor and budle your app (You could possibly do it on the same server but we haven't verfied it)
- Basic familiarity with using the Linux command line (terminal)
- We will be installing a Personal Budget App in production. The source code of this app is available here. Replace the word budget with the name of you app
- Our Production server has an IP of 192.168.1.1
- Our development server on which the Meteor App was developed has an IP of 192.168.1.2
Installation
This section covers the installation and configuration of various software components required to get the Meteor app running in productionStep 1 - SSH in to your server and get root access
ssh ubuntu@192.168.1.1
sudo su
apt-get update
Step 2 - Install and Configure Nginx
apt-get install -y nginx
Create a the following file /etc/nginx/sites-available/budget vim /etc/nginx/sites-available/budget
Cut and paste following contents in the file1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 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; # if this is not a default server, remove "default_server" listen [::]:80 default_server ipv6only=on; root /usr/share/nginx/html; # root is irrelevant index index.html index.htm; # this is also irrelevant server_name 192.168.1.1; # the domain on which we want to host the application. Since we set "default_server" previously, nginx will answer all hosts anyway. # redirect non-SSL to SSL location / { rewrite ^ https://$server_name$request_uri? permanent; } } # HTTPS server server { listen 443 ssl spdy; # we enable SPDY here server_name 192.168.1.1; # this domain must match Common Name (CN) in the SSL certificate root html; # irrelevant index index.html; # irrelevant ssl_certificate /etc/nginx/ssl/budget.pem; # full path to SSL certificate and CA certificate concatenated together ssl_certificate_key /etc/nginx/ssl/budget.key; # full path to SSL key # 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; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK'; # 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://0.0.0.0:8080; 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; } } } |
Step 3 - Create Keys using OpenSSL
1 2 3 4 5 6 7 8 | mkdir /etc/nginx/ssl chmod 0700 /etc/nginx/ssl cd /etc/nginx/ssl/ openssl genrsa -des3 -out budget.key 2048 openssl req -new -key budget.key -out budget.csr cp budget.key budget.key.org openssl rsa -in budget.key.org -out budget.key openssl x509 -req -days 365 -in budget.csr -signkey budget.key -out budget.pem |
Step 4 - Verify Nginx Install
1 2 | rm /etc/nginx/sites-enabled/default ln -s /etc/nginx/sites-available/budget /etc/nginx/sites-enabled/budget |
1 2 | nginx -t nginx -s reload |
Step 5 - Install MongoDB
1 2 | apt-get install -y mongodb-server netstat -ln | grep -E '27017|28017' |
1 2 | tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN unix 2 [ ACC ] STREAM LISTENING 13178 /tmp/mongodb-27017.sock |
Step 6 - Install NodeJS
1 2 | curl -sL https://deb.nodesource.com/setup_4.x | bash - apt-get install -y nodejs |
Step 7 - Create a System User
1 | adduser --disabled-login budget
|
Step 8 - Install Upstart and create the upstart script
1 | apt-get install upstart upstart-sysv
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # upstart service file at /etc/init/budget .conf description "Meteor.js (NodeJS) application" author "Daniel Speichert " # When to start the service start on started mongodb and runlevel [2345] # When to stop the service stop on shutdown # Automatically restart process if crashed respawn respawn limit 10 5 # we don't use buil-in log because we use a script below # console log # drop root proviliges and switch to mymetorapp user setuid budget setgid budget script export PATH=/opt/local/bin:/opt/local/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin export NODE_PATH=/usr/lib/nodejs:/usr/lib/node_modules:/usr/share/javascript # set to home directory of the user Meteor will be running as export PWD=/home/budget export HOME=/home/budget # leave as 127.0.0.1 for security export BIND_IP=127.0.0.1 # the port nginx is proxying requests to export PORT=8080 # this allows Meteor to figure out correct IP address of visitors export HTTP_FORWARDED_COUNT=1 # MongoDB connection string using budget as database name export MONGO_URL=mongodb://localhost:27017/budget # The domain name as configured previously as server_name in nginx export ROOT_URL=https://192.168.1.1 # optional JSON config - the contents of file specified by passing "--settings" parameter to meteor command in development mode export METEOR_SETTINGS='{ "somesetting": "someval", "public": { "othersetting": "anothervalue" } }' # this is optional: http://docs.meteor.com/#email # commented out will default to no email being sent # you must register with MailGun to have a username and password there # export MAIL_URL=smtp://postmaster@mymetorapp.net:password123@smtp.mailgun.org # alternatively install "apt-get install default-mta" and uncomment: # export MAIL_URL=smtp://localhost exec node /home/budget/bundle/main.js >> /home/budget/budget.log end script |
Step 9 - Bundle your App - We are performing this step on a different Ubuntu 16.04 server
If you have your own app you can skip using the budget appInstall Meteor
1 | curl https://install.meteor.com/ | sh
|
1 | apt-get install git
|
1 2 3 4 | mkdir personal-budget cd personal-budget/ git init git pull https://github.com/mehrashiv/personal-budget.git |
1 | meteor
|
Build your App
1 | meteor build .
|
1 | scp personal-budget.tar.gz ubuntu@192.168.1.1:/home/ubuntu
|
Step 10 - Setup your App
Drop in to the budget user directory and copy your app1 2 | cd /home/budget cp /home/ubuntu/personal-budget.tar.gz . |
1 | tar -zxf personal-budget.tar.gz
|
1 | apt-get install -y g++ make python
|
1 2 3 4 | cd /home/budget/bundle/programs/server/ npm install npm install bcrypt reboot |
1 2 3 4 | sudo su cd /home/budget/bundle/programs/server/npm/node_modules/meteor/ rm -rf npm-bcrypt/ start budget |
Hey can you explain me how to do it on a http server and host 2 or more apps in the same server ?
ReplyDeleteHi Oscar,
ReplyDeleteI had started exploring that, but rather than run everything on one server, I have started using docker which is light weight and will enable us to run a container for each application.
Thank you so much! I've been looking for a tutorial like this for a long time.
ReplyDelete