<p>The layer that you're missing is nginx proxy. See my toy Mafia Game project here how to do it:</p>
<ul>
<li>Shell deployment project (uses either Docker compose or k8s) - <a href="https://github.com/taleodor/mafia-deployment" rel="nofollow noreferrer">https://github.com/taleodor/mafia-deployment</a></li>
<li>Vue.js frontend - <a href="https://github.com/taleodor/mafia-vue" rel="nofollow noreferrer">https://github.com/taleodor/mafia-vue</a></li>
<li>Express.js backend - <a href="https://github.com/taleodor/mafia-express" rel="nofollow noreferrer">https://github.com/taleodor/mafia-express</a></li>
<li>(Optional) detailed write-up about CI/CD and how it's built from DevOps prospective - <a href="https://itnext.io/building-kubernetes-cicd-pipeline-with-github-actions-argocd-and-reliza-hub-e7120b9be870" rel="nofollow noreferrer">https://itnext.io/building-kubernetes-cicd-pipeline-with-github-actions-argocd-and-reliza-hub-e7120b9be870</a></li>
</ul>
<p>The missing piece in your case is nginx proxy that you use in your UI.</p>
<p>So what you need to do is to define some location for your api - i.e. <code>/api</code>. Then your proxy it via nginx - see my nginx configuration for the project above here - <a href="https://github.com/taleodor/mafia-vue/tree/master/nginx" rel="nofollow noreferrer">https://github.com/taleodor/mafia-vue/tree/master/nginx</a>. At the same time it's highly recommended for performance to deploy static resources on the same nginx.</p>
<p>Use Dockerfile to define environment variables and defaults, i.e. in my project - <a href="https://github.com/taleodor/mafia-vue/blob/master/Dockerfile" rel="nofollow noreferrer">https://github.com/taleodor/mafia-vue/blob/master/Dockerfile</a></p>
<p>Finally, you can update configuration via environment variables in your docker-compose yaml or k8s definitions.</p>

CC BY-SA 4.0
2020-07-02T18:50:11.280Z
I updated my repository with this solution and everything seems nice now.
But, just one more question, what are these configurations that can be updated with environment variables in docker-compose that you suggested? Is there any guide that I could follow?
Sinayra
CC BY-SA 4.0
2020-07-02T21:11:25.777Z
You don't have to parametrize anything right away. But as you go you may notice certain things that need parametrizing - so for those things you may create env variables. 

Personally, I usually always parametrize host names and ports for upstreams - because name conventions may be sometimes different between local docker, docker-compose and k8s.

Sometimes you will find other things later to parametrize - but no hard rules here.

+ Rarely, there may be more complex cases, where you can include more sophisticated templating engine if needed.
taleodor
CC BY-SA 4.0
2020-07-01T00:21:13.540Z
2020-07-01T00:21:13.540Z
taleodor
<p>I'm studying Docker and how to properly publish my containers coding a very simple web application. It has only two containers, backend and frontend. I've published the source code here: <a href="https://github.com/sinayra/hello-private-world" rel="nofollow noreferrer">https://github.com/sinayra/hello-private-world</a></p>
<p>If I run locally each node application, its works &quot;fine&quot; (everything is public, but this is not what I want in the end of the day). Then, I created Dockerfile for each container, to try to simulate a real application. For the frontend, I exposed the port 3000 to access from the host. However, I don't want to expose the port 3333 for the host, and, because of that, my front can't fetch the data from the back.</p>
<p>Here is my index.html from the frontend.</p>
<pre><code>&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;Hello Public World&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Message from backend:&lt;/h1&gt;
    &lt;p id=&quot;backend&quot;&gt;&lt;/p&gt;

    &lt;script&gt;
      const back = document.getElementById(&quot;backend&quot;);
      const url = &quot;http://localhost:3333/&quot;; //I tried backend:3333, but without success

      fetch(url)
        .then((resp) =&gt; resp.json()) // Transform the data into json
        .then(function (data) {
          back.innerHTML = data.message;
        });
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Its Dockerfile:</p>
<pre><code># pull official base image
FROM node:lts

# set working directory
WORKDIR /usr/src/app

# install app dependencies
COPY package.json ./
RUN npm install

# add app
COPY . ./

EXPOSE 3000

# start app
CMD [&quot;npm&quot;, &quot;run&quot;, &quot;start&quot;]
</code></pre>
<p>My index.js from backend:</p>
<pre><code>const express = require(&quot;express&quot;);
const app = express();
const cors = require(&quot;cors&quot;);
const port = 3333;

const allowlist = [&quot;http://localhost:3000&quot;];
const corsOptions = {
  origin: allowlist,
  methods: &quot;GET&quot;,
  preflightContinue: false,
  optionsSuccessStatus: 204,
};
app.use(cors(corsOptions));

app.use(express.json());
app.get(&quot;/&quot;, (req, res) =&gt; {
  console.log(&quot;GET /&quot;);
  res.json({ message: &quot;Hello Private World!&quot; });
});

app.listen(port, () =&gt;
  console.log(`Example app listening at http://localhost:${port}`)
);
</code></pre>
<p>Its Dockerfile:</p>
<pre><code># pull official base image
FROM node:lts

# set working directory
WORKDIR /usr/src/app

# install app dependencies
COPY package.json ./
RUN npm install

# add app
COPY . ./

#EXPOSE 3333

# start app
CMD [&quot;npm&quot;, &quot;run&quot;, &quot;start&quot;]
</code></pre>
<p>And the Docker compose file</p>
<pre><code>version: &quot;3.8&quot;
services:

  backend:
    image: helloworld-private
    build:
      context: ./backend
      dockerfile: Dockerfile
    working_dir: /usr/src/app
    container_name: &quot;express_container&quot;
    volumes:
      - ./backend/:/usr/src/app
      - /usr/src/app/node_modules
    networks: 
      - webappnetwork
    expose:
      - &quot;3333&quot;

  web:
    image: helloworld-public
    build:
      context: ./web
      dockerfile: Dockerfile
    working_dir: /usr/src/app
    container_name: &quot;liveserver_container&quot;
    links:
      - backend
    volumes:
      - ./web/:/usr/src/app
      - /usr/src/app/node_modules
    environment:
      - PORT=3000
    networks: 
      - webappnetwork
    ports: 
      - &quot;3000:3000&quot;

networks:
  webappnetwork:
    driver: bridge
</code></pre>
<p>Is there any abstraction layer that I'm missing?</p>

CC BY-SA 4.0
2020-09-03T17:34:22.340Z
Side Note: I see what you did there with that title phrasing. ;)
J. Scott Elblein
CC BY-SA 4.0
2020-09-04T18:07:21.707Z
omg... I swear it was unintentional
Sinayra
<docker><docker-compose><containers><security><node.js>
How not expose my backend
Sinayra
# How not expose my backend

(Asked by: username_0 on 2020-06-29)

I'm studying Docker and how to properly publish my containers coding a very simple web application. It has only two containers, backend and frontend. I've published the source code here: https://github.com/sinayra/hello-private-world
If I run locally each node application, its works "fine" (everything is public, but this is not what I want in the end of the day). Then, I created Dockerfile for each container, to try to simulate a real application. For the frontend, I exposed the port 3000 to access from the host. However, I don't want to expose the port 3333 for the host, and, because of that, my front can't fetch the data from the back.
Here is my index.html from the frontend.

  
    Hello Public World
  
  
    Message from backend:
    

    
  


Its Dockerfile:
# pull official base image
FROM node:lts

# set working directory
WORKDIR /usr/src/app

# install app dependencies
COPY package.json ./
RUN npm install

# add app
COPY . ./

EXPOSE 3000

# start app
CMD ["npm", "run", "start"]

My index.js from backend:
const express = require("express");
const app = express();
const cors = require("cors");
const port = 3333;

const allowlist = ["http://localhost:3000"];
const corsOptions = {
  origin: allowlist,
  methods: "GET",
  preflightContinue: false,
  optionsSuccessStatus: 204,
};
app.use(cors(corsOptions));

app.use(express.json());
app.get("/", (req, res) => {
  console.log("GET /");
  res.json({ message: "Hello Private World!" });
});

app.listen(port, () =>
  console.log(`Example app listening at http://localhost:${port}`)
);

Its Dockerfile:
# pull official base image
FROM node:lts

# set working directory
WORKDIR /usr/src/app

# install app dependencies
COPY package.json ./
RUN npm install

# add app
COPY . ./

#EXPOSE 3333

# start app
CMD ["npm", "run", "start"]

And the Docker compose file
version: "3.8"
services:

  backend:
    image: helloworld-private
    build:
      context: ./backend
      dockerfile: Dockerfile
    working_dir: /usr/src/app
    container_name: "express_container"
    volumes:
      - ./backend/:/usr/src/app
      - /usr/src/app/node_modules
    networks: 
      - webappnetwork
    expose:
      - "3333"

  web:
    image: helloworld-public
    build:
      context: ./web
      dockerfile: Dockerfile
    working_dir: /usr/src/app
    container_name: "liveserver_container"
    links:
      - backend
    volumes:
      - ./web/:/usr/src/app
      - /usr/src/app/node_modules
    environment:
      - PORT=3000
    networks: 
      - webappnetwork
    ports: 
      - "3000:3000"

networks:
  webappnetwork:
    driver: bridge

Is there any abstraction layer that I'm missing?

**Tags:** docker, docker-compose, containers, security, node.js

> **Comments:**
> **username_1**: Side Note: I see what you did there with that title phrasing. ;)  
> **username_0**: omg... I swear it was unintentional  

---

## 1 answers

### Answer by username_2 on 2020-07-01. Score: 2 | Accepted answer

The layer that you're missing is nginx proxy. See my toy Mafia Game project here how to do it:

* Shell deployment project (uses either Docker compose or k8s) - <https://github.com/username_2/mafia-deployment>
* Vue.js frontend - <https://github.com/username_2/mafia-vue>
* Express.js backend - <https://github.com/username_2/mafia-express>
* (Optional) detailed write-up about CI/CD and how it's built from DevOps prospective - <https://itnext.io/building-kubernetes-cicd-pipeline-with-github-actions-argocd-and-reliza-hub-e7120b9be870>

The missing piece in your case is nginx proxy that you use in your UI.

So what you need to do is to define some location for your api - i.e. `/api`. Then your proxy it via nginx - see my nginx configuration for the project above here - <https://github.com/username_2/mafia-vue/tree/master/nginx>. At the same time it's highly recommended for performance to deploy static resources on the same nginx.

Use Dockerfile to define environment variables and defaults, i.e. in my project - <https://github.com/username_2/mafia-vue/blob/master/Dockerfile>

Finally, you can update configuration via environment variables in your docker-compose yaml or k8s definitions.

> **Comments:**
> **username_0**: I updated my repository with this solution and everything seems nice now. But, just one more question, what are these configurations that can be updated with environment variables in docker-compose that you suggested? Is there any guide that I could follow?  
> **username_2**: You don't have to parametrize anything right away. But as you go you may notice certain things that need parametrizing - so for those things you may create env variables.   Personally, I usually always parametrize host names and ports for upstreams - because name conventions may be sometimes different between local docker, docker-compose and k8s.  Sometimes you will find other things later to parametrize - but no hard rules here.  + Rarely, there may be more complex cases, where you can include more sophisticated templating engine if needed.  

---

