Mac OS X, Vagrant, Docker, Nginx, Node - how do ports play together? - node.js

I have a simple nginx, node.js setup that I want to migrate into the Vagrant, Docker world. I'm not sure how to handle IPs and ports.
My goal is it to see my Hello World in the Browser, best case on port 80, simply by calling my host http://example.com.
UPDATE
I found the solution myself - I created a simple boilerplate here:
https://github.com/ezmilhouse/docker
Feel free to go on from here.
app.js
var app = express();
app.route('*').all(function(req, res) {
res.send('Hello World!');
});
app.listen(2000)
nginx.conf
upstream example.com {
# using the vagrant private network IP (I guess?)
# using the node port
server 192.168.33.10:2000
}
server {
# ports nginx server is listen to
listen 80;
listen 443;
location / {
# upstream proxy
proxy_pass http://example.com;
# ...
}
}
Vagrantfile.proxy
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.provision "docker"
# settimg a hostname that matches nginx upstream (I guess?)
config.vm.hostname = "example.com"
# setting a private network IP, node.js and nginx run on this IP (i guess?)
config.vm.network "private_network", ip: "192.168.33.10"
end
Vagrantfile
Vagrant.configure("2") do |config|
config.vm.define "nginx" do |app|
# forward the nginx port (I guess?)
app.vm.network "forwarded_port", guest: 80, host: 80
app.vm.provider "docker" do |d|
d.build_dir = "./docker/nginx"
d.vagrant_vagrantfile = "./Vagrantfile.proxy"
end
end
config.vm.define "node" do |app|
# forward the node port (I guess?)
app.vm.network "forwarded_port", guest: 2000, host: 2000
app.vm.provider "docker" do |d|
d.build_dir = "./docker/node"
d.vagrant_vagrantfile = "./Vagrantfile.proxy"
end
end
end
/nginx/Dockerfile
# ...
EXPOSE ["80"]
/node/Dockerfile
# ...
EXPOSE ["2000"]
Mac OS X /etc/hosts
192.168.33.10 example.com
I was expecting to call http://192.168.33.10 in the browser to see my Hello World via nginx and http://192.168.33.10:2000 to see the node instance. Therefore the host example.com does not work either.
What do I do wrong?

I created the fork and made pull request to your repo.
The main idea: do not use provisioning for docker containers.
More information your can find in this article

Related

setting up testing environment with Vagrant Virtual Machine and Nginx

I'm trying to set up a local web testing environment with Vagrant on a centos/6 virtual machine
In the vagrant configuration I set: config.vm.network "forwarded_port", guest: 80, host: 8080
Inside of the vagrant box if I type: hostname -I it gives me a result of
10.0.2.15
In the vagrant box, nginx is already set and I do have a SSL certification and HTTPS connection set up:
server {
listen 443;
server_name 127.0.0.1:8000;
...(other configurations including ssl_certificate,
ssl_certificate_key,protocols and cipher)
...(other values that I think its not relevant)
location / {
if ($http_host != 127.0.0.1:8000) {
return 444;
}
proxy_pass http://127.0.0.1:8000;
}
And then I have:
server {
listen 80 default;
server_name ~^;
return 302 https://127.0.0.1:8000$request_uri;
}
In my vagrant box, if I use curl to get the content at 127.0.0.1:8000: curl 127.0.0.1:8000, I'm able to successfully get the expected content
From my host operating system, when I'm using chrome to request access to 127.0.0.1, it simply says The connection was reset. and the error exception code is ERR_CONNECTION_RESET
My best guess is this has to deal with my SSL configuration?
Not sure if this will help, I run vagrant and use Virtualbox as my hypervisor. You will need to check what the vagrant box is doing for NAT. On mine, out of the box it is 192.169.33.10 and that will get to my dev box. Assumes port forwarding is set right and no firewall.
What does 192.168.33.10:8080 do?

throw err when connecting to mongodb in VM using node.js

I'm running my mongodb in virtualbox using vagrant. I'm trying to connect to the database on my host machine using node.js, but I get thrown a strange err when trying to do so. This is the code i'm running.
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:6600/test";
MongoClient.connect(url, function(err, db){
if (err){
throw err;
}
console.log("Database created!");
db.close();
});
This is the error that is shown in command line.
C:\Users\Morgan\Desktop\testingGrounds>node createMongoDB.js
C:\Users\Morgan\Desktop\testingGrounds\node_modules\mongodb\lib\mongo_client.js:421
throw err
^
[object Object]
And this is a relevant part of the Vagrantfile.
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# config.vm.network "forwarded_port", guest: 80, host: 8080
# nginx
config.vm.network "forwarded_port", guest: 80, host: 6600
# # development site
config.vm.network "forwarded_port", guest: 3000, host: 6660
# db browser port
config.vm.network "forwarded_port", guest: 7474, host: 6666
# test port
config.vm.network "forwarded_port", guest: 8800, host: 6606
If you are using vagrant for some dev/test running on local, just use a static ip it will simplify your life.
You can remove all the forwarded ports line from your Vagrantfile and replace with:
config.vm.network :private_network, ip: "192.168.33.10"
In the VM, you need to make sure mongo is bound to this IP or 0.0.0.0 so it can listen to all network interfaces, in the /etc/mongod.conf file, make sure to have
bind_ip=0.0.0.0
or
bind_ip=192.168.33.10
In your node code, you will need to replace the url for mongo to mongodb://192.168.33.10:27017/test (assuming mongo is running on port 27017; if you have made a change in your conf file, align here)

Can't access a node express app from vagrant host machine

I am new to networking and assigning ports and things of that nature. I have been using vagrant for some time and have never had any problems trying to get a test environment up and then accessing it through the host machine browser. The set up for this in my Vagrantfile is this:
# network stuff
config.vm.network "forwarded_port", guest: 8000, host: 8000
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.hostname = "test-box-debian"
Now I am trying to learn a bit about node.js, and every tutorial says I can run npm start and indeed this works fine. I can call wget localhost:3000 (port 3000 being the default in express) and in return get the index.html default page from express.
However when I try and access `192.168.33.10:3000' from the host browser, it doesn't work. I can run netstat and get the following as a result:
sudo netstat -ltpn | grep 3000
tcp6 0 0 :::3000 :::* LISTEN 17238/node
I can see that something doesn't look right but I just don't know enough about ports and networking to know what is wrong and how to fix it.
First, ensure your server is listening to the right IP and that you haven't bound the Express listener elsewhere:
.listen(3000), NOT .listen(3000, '127.0.0.1')
Alternatively, try binding the Express server to your private IP or to the wildcard IP and see if that resolves your connectivity issues:
// Wildcard (All IP's) binding
.listen(3000, '0.0.0.0')
// Specific binding
.listen(3000, '192.168.33.10')
Lastly, port 3000 may not be accessible from the host. If none of the above options in your server code work, try adding the following line to your Vagrantfile:
config.vm.network "forwarded_port", guest: 3000, host: 3000
Make sure you don't have a firewall on your VM blocking the port:
sudo iptables -I INPUT -p tcp --dport 3000 -j ACCEPT
Found the answer over at https://stackoverflow.com/a/28474080/1772120.
If your vagrant setting is like
# network stuff
config.vm.network "forwarded_port", guest: 8000, host: 8000
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.hostname = "test-box-debian"
Then your node app should listen to 192.168.33.10:8000
const http = require('http');
const hostname = '192.168.33.10';
const port = 8000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type','text/plain');
res.end('Hello World\n');
})
server.listen(port, hostname, () => {
console.log('Server running at');
})

Simple example of Vagrantfile / Dockerfile to run node app

I'm having difficulty trying to get a simple node app running inside a docker container hosted using vagrant.
This page explains the basic approach: https://www.vagrantup.com/blog/feature-preview-vagrant-1-6-docker-dev-environments.html
What I am unable to do is access the node app from my machine - in theory I believe I should be able to see my "hello world" style node/express app at localhost:8181...
Below is what I have so far:
Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |d|
d.build_dir = "."
d.ports = ["8080:5000"]
# Is this necessary if EXPOSE is used in Dockerfile?
d.expose = ["5000"]
d.remains_running = true
d.volumes = ["/shared"]
end
config.vm.network "forwarded_port", guest: 8080, host: 8181
config.vm.synced_folder "~/Documents/shared", "/shared"
end
Dockerfile:
# DOCKER-VERSION 0.8.0
FROM centos:6.4
RUN rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
RUN yum install -y npm ImageMagick
ADD . /app
# Not necessary because node_modules are bundled
# RUN cd /app; npm install
EXPOSE 5000
CMD ["node", "/app/index.js"]
I've followed the documentation as closely as possible but just can't seem to achieve what I'm after. Any ideas?
Note: node app is working when running normally ie $ node index and accessed at localhost:5000
Thanks in advance
EDIT:
index.js:
var express = require('express'),
http = require('http');
var app = express();
var port = 5000;
app.get('/', function(req, res) {
res.send('Hello World');
});
var server = http.createServer(app);
server.on('listening', function() {
console.log('Express server listening on port ' + port);
});
server.listen(port, '0.0.0.0');
setInterval(function(){
console.log('running');
}, 5000);
package.json:
{
"name": "vagrant-docker-node",
"version": "0.0.0",
"dependencies": {
"express": "^4.1.0"
},
"main": "index.js"
}
I actually ran into the same issue. Not sure if it's intended behavior or bug but setting forwarded_port in a Vagrantfile with a Docker provider does nothing on the host boot2docker machine.
Unless I'm missing something, you have to either provide your own host machine with another Vagrantfile opening the correct ports or modify the one provided by Vagrant.
Approach 1: Provide your own host machine (based on boot2docker)
Here's the base Vagrantfile for the boot2docker host: boot2docker Vagrantfile. You need to edit a copy of this Vagrantfile and set your forwarded ports here.
Then, in your Docker app Vagrantfile, modify as follow:
config.vm.provider "docker" do |d|
# Specify here the path to the updated host Vagrantfile
d.vagrant_vagrantfile = "../boot2docker/Vagrantfile"
... # edited out for clarity
end
Make sure you point to your updated host machine. Here I set it to an upper level shared directory because if you want to share this machine between multiple Docker apps with seperate Vagrantfiles, you'll have to point to the same host Vagrantfile (otherwise it'll try to spin up new host VMs).
Approach 2: Update Vagrant's host machine
You can also update the Vagrantfile automatically used by Vagrant which is located in %VAGRANT_HOME%/data/docker-host/Vagrantfile. Modify the file to open your ports.
Then do a vagrant global-status to get the ID of the host machine and vagrant reload machineId to restart the machine which will trigger the port re-open and update.
I'm not sure if there's a better or sanctionned way to do this but that's the only way I could have the ports forwarded all the way from Docker container to physical machine.
Shouldn't you forward the exposed port 5000 from Docker to your host, using Vagrant?
config.vm.network "forwarded_port", guest: 5000, host: 8181
(to get your app reachable on port 8181 from your host browser, for example)
Instead of:
config.vm.network "forwarded_port", guest: 8080, host: 8181
Flows/redirects summary:
Docker container Vagrant VM Your computer
:8080 => :5000 => :8181
What's your host OS (the one you execute the "vagrant" command on)? If it's non-Linux (e.g. OSX or Windows) then your Docker container will be riding on top of a Linux VM (usually TinyCore Linux inside VirtualBox), and the port forwarding will be done from inside that VirtualBox into the Docker container.
You should see evidence of port forwarding taking effect by looking for listening TCP sockets using "netstat -tlpn" (on Linux) or "netstat -an" (on OSX)

Vagrant host port ignored

In my Vagrantfile I have the definition of my development machine with a private network ip of 192.168.33.10 and a forwarded port of "guest=80, host=8888", but when a run my vagrant enviroment and I try to run curl -i 192.168.33.10:8888 I get an error saying 'Failed connect to 192.168.33.10:8888; connection refused', but when I try to connect to 192.168.33.10:80 everything it's ok.
My Vagrantfile is:
Vagrant::configure("2") do |config|
config.vm.box = "precise32"
config.vm.define :web do |www|
www.vm.hostname = "apache"
www.ssh.max_tries = 10
www.vm.network :forwarded_port, guest: 80, host: 8888 # Apache port
www.vm.network :private_network, ip: "192.168.33.10"
www.vm.synced_folder "www", "/var/www", :extra => 'dmode=777,fmode=777'
end
end
Why this happens? is vagrant ignoring the forwarded port?
By default Vagrant Boxes use NAT mode, it means that the guests are behind a router (VirtualBox Networking engine between the host and the guest) which maps traffic from and to the virtual machine transparently. The guests are invisible and unreachable from the host.
That's why we need port forwarding. Otherwise services running on guest wont' be accessible.
In your case, you are using Private Network, the guest will be assigned a private IP address that ONLY the host can access, which is 192.168.33.10.
The proper way to access web hosted on the guest is => http://192.168.33.10 from the host.
You have the port forwarding part in the Vagrantfile
www.vm.network :forwarded_port, guest: 80, host: 8888 # Apache port
It is forwarding guest port 80 to your host's 8888. Because you are NOT using NAT mode I am pretty sure it will be ignored. Try to curl -Is http://localhost:8888.
NOTE: even if it still work somehow, you should be accessing web by => http://localhost:8888/ from your host.

Resources