(skip it if you're in rush)Hi there, I'm deploying for the first time a meteor app and it's not easy to have a straight forward explanation for the all process. I got a lot disturbed between different choices, wasting time with a heroku account creation, passenger and other noisy tools/documentations which seem to be made in order to discourage people and make them pay for services which solve a problem but add another layer of documentation/community who suggests you to add another npm package and so on...
This tutorial is inspired of this passenger tutorial combined with apache reverse proxy setup in a way that fit me better, simpler, more vanilla, without passenger.
I wrote this tutorial at first as a reminder for myself for the next time I'll be willing to deploy another application. I also think that it may be useful for someone else so I publish it and put some efforts for your eye/mind comfort.
I don't pretend to know better or what, I just digged my way with oldschool, simple and trusty tools in my opinion, I'm not really sure about the quality of this setup but it actually works for me
Don't hesitate to correct and suggest, tell me if the solution that I provide doesn't work for you, if something doesn't make sense, I'll update this tutorial consequently.
(Start here if you're in rush)At the end of this tutorial, you will have your meteor application deployed and running on a subdomain like https://myapp.domain.com, usable simply by typing the address on your browser and by the android client using Apache2/nginx on your vps/dedicated.
Oh and of course redirection http to https included, we're not living in the caveman days.
At this point, I consider that apache2 and mongodb are already installed and running on your server with this configuration:
/var/www/html (default Apache2 configuration or your current website)Everything exclusively related to our meteor application myapp will have the same name.
On your development laptop/raspberry pi/piratebox, whatever the thing your meteor app is developed on:
user@development ~/myapp $ meteor build --server-only ../myapp.tar.gz
user@development ~/myapp $ scp ../myapp.tar.gz user@server.com
user@development ~/myapp $ ssh user@server.com
user@server.com's password:
Welcome to your god damn server (•̀ᴗ•́)و
server ~ $ ls
...
myapp.tar.gz
...
By default on Ubuntu, apache2 uses /var/www/ folder, but of course it depends on your distros and stuffs. If you use arch linux, it's gonna be /srv which make a certain sense. For other distro/OS I don't know.
user@server ~ $ sudo mkdir /var/www/myapp
user@server ~ $ sudo tar xzf ~/myapp.tar.gz -C /var/www/myapp
ok cool my friends, if you ls, it looks like this:
user@server $ sudo ls /var/www/myapp
bundle/
user@server $ sudo ls /var/www/myapp/bundle
main.js programs README server star.json
Ok now we are about to run nodejs with your 364 npm dependencies that will get updated regularly. Writting a javascript code which scan the directories arround, create files etc... is easier than stealing a lollipop to a kid.
(。_°)☆\(-_– )
We gonna create an user dedicated to the meteor app, with his app folder access only.
myappuser@server ~ $ sudo adduser myapp
Don't care about the password, let blank to disable it (no login possible unless by root/sudoer user) or generate a strong one, this user is not supposed to be used as a regular one, don't type your personal password or 1234.
myapp useruser@server ~ $ sudo chown -R myapp /var/www/myapp
For convenience, I create a symbolic link in myapp's home
user@server ~ $ sudo su myapp
myapp@server /home/user $ ln -s /var/www/myapp ~/app && cd ~/app/bundle
myapp@server ~/app/bundle $
Alright, we're ready to rock now.
myapp@server ~/app/bundle $ (cd programs/server && npm install)
myapp@server ~/app/bundle $ PORT=3000 MONGO_URL=mongodb://myapp:password@localhost:27017/myapp ROOT_URL=http://localhost node main.js
Browse on http://mydomain.com:3000 and you should be able to use your application, of course, your app is not working over ssl (https/port 443) and you shouldn't let it as it is, but isn't it feeling good to finally see it working in production \\ ٩( ᐛ )و // ?
(⌐▨_▨) - Ok now you can kill it (ctrl+c) and come back to the regular user we will make a proper reverse proxy with apache2.
^C
myapp@server ~/app/bundle $ exit
user@server ~ $
user@server ~ $ sudo a2enmod proxy
user@server ~ $ sudo a2enmod proxy_http
More information here: Enabling Necessary Apache Modules
user@server ~ $ sudo vim /etc/apache2/sites-enabled/000-default.conf
<VirtualHost *:80>
ServerName mydomain.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
[...]
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
[...]
RewriteEngine on
# main domain running php in /var/www/html
RewriteCond %{SERVER_NAME} = mydomain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
# your application domain
RewriteCond %{SERVER_NAME} = myapp.mydomain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
# another application ?
RewriteCond %{SERVER_NAME} = myapp2.mydomain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
[...] and so on [...]
</VirtualHost>
user@server ~ $ sudo vim /etc/apache2/sites-enabled/000-default-le-ssl.conf:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName myapp.mydomain.com
[...]
SSLProxyEngine On
ProxyPreserveHost On
ProxyPass /websocket ws://localhost:3000/websocket
ProxyPassMatch ^/sockjs/(.*)/websocket ws://localhost:3000/sockjs/$1/websocket
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
</VirtualHost>
</IfModule>
user@server ~ $ sudo systemctl restart apache2
user@server ~ $ sudo su myapp
myapp@server /home/user $ cd ~/app/bundle
myapp@server ~/app/bundle $ nohup `PORT=3000 MONGO_URL=mongodb://myapp:password@localhost:27017/myapp ROOT_URL=http://localhost node main.js` &
nohup: ignoring input and appending output to 'nohup.out'
myapp@server ~/app/bundle $ exit
user@server ~ $ exit
user@development ~/myapp $ echo "[x] meteor application deployment" >> completed-tasks.txt
Now you can browse on https://myapp.mydomain.com
Note: http://mydomain.com:3000 is still usable tho, but you can forbid the access with iptables