skip to Main Content

I am farely unexperienced in devops topics and I have to approach migrating from heroku to a VPS in the coming days.

I have 3 nodejs apps running on heroku, that I need to migrate to a VPS using docker. What would be the best approach, to host and securely run multiple apps on a single machine? I have read a little about docker compose and nginx, but it is not clear for me how to approach this with 3 node servers that all require their own mongoDB as well.

Is there a way to set up all apps in a single file and fire them up all at once, or what would be the best approach here?

2

Answers


  1. You can use Docker Compose to easily create multiple apps that can connect to eachother via container name through the internal network DNS.

    There are a lot of ways to do it. If you have three slightly applications, each with their own MongoDB instance, you could run them all on one compose, or in three different composes.

    version: "3.9"
    services:
      nodejs-1:
        image: your-app-1
        ports:
          - "81:80"
        environment:
          - database: db-1:27017
      db-1:
        image: mongodb
    
      nodejs-2:
        image: your-app-2
        ports:
          - "82:80"
        environment:
          - database: db-2:27017
      db-2:
        image: mongodb
    
      nodejs-3:
        image: your-app-3
        ports:
          - "83:80"
        environment:
          - database: db-3:27017
      db-3:
        image: mongodb
    

    With this method, the three apps and three databases will run on a single network. If you want to isolate them, you could split this into three different docker-compose files. A private network is then created for each. I’ve added an example "database" environmental variable where your app can get the database DNS name from, but obviously this will vary depending on your application configuration.

    You can expand on this with a single Nginx instance if you run as one big network and route traffic to your node.js instances without exposing the ports directly (80:80 etc.) and instead open ports to your Nginx instance.

    This guide is helpful for setting up a reverse proxy with Docker Compose.
    https://www.domysee.com/blogposts/reverse-proxy-nginx-docker-compose

    Login or Signup to reply.
  2. I think a lot of it depends upon what sort of load are you expecting on those APIs and what are your expectations in terms of availability. Some more important things to consider; how interconnected are these apis, do you expect each of them to fail if one or both of the other services are not available, etc. Since these things are not specified I will try to answer for simple scenarios.

    If it is a pet project and there is no requirement for it to have high availability or heavy load on the APIs (and you are trying to minimise cost)

    This case would be simple. Deploy all three APIs and their respective mongodb instances on a single VPS using docker-compose. The setup would be fairly simple and you would have 6 docker containers running on one VPS. Each nodejs startup will have to wait for their respective mongodb service to start but this can be achieved very easily by something similar to this wait-for-it script.

    To front these services on a single port you should use nginx as a reverse proxy. Nginx can be run as a service on the VPS itself or for portability you could include nginx as part of the docker-compose as well. This will allow you to port the docker-compose file on any VPS in future and startup the whole environment with a single command. Below is what your docker-compose would look like with 3 node APIs, 3 mongodb services and nginx;

    services:
      node-api1:
        image: node-api1
      environment:
        MONGO_HOST: api1-db
        ...
    
      node-api2:
        image: node-api2
      environment:
        MONGO_HOST: api2-db
        ...
    
      node-api3:
        image: node-api3
      environment:
        MONGO_HOST: api3-db
        ...
    
      api1-db:
        image: mongo
      environment:
          ...
    
      api2-db:
        image: mongo
      environment:
          ...
    
      api3-db:
        image: mongo
      environment:
          ...
    
      nginx:
        image: nginx:alpine
      ports:
        - 80:80
      volumes:
        - ./nginx.conf:/etc/nginx/nginx.conf
    

    All three mongo and node services will be on a single docker network and will be able to talk to each other using their service names as host name instead of having to mess with any hostname/ip addresses. Once again this makes portability a lot easier. The only exposed port is port 80 via nginx and your nginx.conf for reverse proxy will look like this;

    http {
    
        sendfile on;
    
        upstream docker-node-api1 {
          server node-api1:3000;
        }
        upstream docker-node-api2 {
          server node-api2:3000;
        }
        upstream docker-node-api3 {
          server node-api3:3000;
        }
    
        server {
            listen 80;
    
            location /api1/ {
                proxy_pass         http://docker-node-api1;
                proxy_redirect     off;
                proxy_set_header   Host $host:$server_port;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Host $server_name;
            }
    
            location /api2/ {
                proxy_pass         http://docker-node-api2;
                proxy_redirect     off;
                proxy_set_header   Host $host:$server_port;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Host $server_name;
            }
    
            location /api3/ {
                proxy_pass         http://docker-node-api3;
                proxy_redirect     off;
                proxy_set_header   Host $host:$server_port;
                proxy_set_header   X-Real-IP $remote_addr;
                proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header   X-Forwarded-Host $server_name;
            }
        }
    
    }
    

    Of course this is very minimal config and you will have to configure it a more after reading up on nginx reverse-proxy settings but it should give you general idea. If you ever need to move the deplyment to different machine just copy the docker-compose and nginx config and you are good to go.

    Since you are only exposing a single entrypoint port from your vps if you need to setup SSL it will be a lot less hassle. You will be terminating SSL at nginx level and all your internal traffic from api to api and api to mongo will be non-ssl.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search