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.