DEV Community

Philip Perry
Philip Perry

Posted on

Docker configuration with Nginx routing for Vue and Laravel

In my previous post I wrote how to use a different port to have frontend communicate with backend, but the problem with that was that I wasn't able to setup SSL easily. I actually just have Clouflare handle encryption, but it requires that both frontend and backend run on port 80 and I didn't want to use a separate domain for the backend. Thankfully, Nginx can handle the routing based on the path. Basically, I setup Nginx to route everything in the url to the Vue frontend container (running Node), unless the path starts with /api in which case it gets handled by the Laravel backend. You will notice that the Docker containers themselves run on different ports (3000 and 9000 in this case), but only Nginx communicates with them.

Image description

I'm not going to explain everything in here, as there are other articles that do it better. I'm just documenting my settings, as I wasn't able to find any PHP/Laravel tutorial on this.

My folder/file structure:

backend-code (with Laravel structure)

/ nginx
  - default.conf
  - Dockerfile
- docker-compose.yml
- Dockerfile
Enter fullscreen mode Exit fullscreen mode

frontend-code (with Vue structure)

- nginx.conf
- Dockerfile
Enter fullscreen mode Exit fullscreen mode

This is the Nginx config file

upstream frontend {
  server frontend:3000;

upstream backend {
  server backend:9000;

server {
  listen 80;
  index index.php index.html;
  error_log  /var/log/nginx/error.log;
  access_log /var/log/nginx/access.log;
  root /var/www/html/public;

  location / {
      proxy_pass http://frontend;

  location /api {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;

  # Nginx Pass requests to PHP-FPM
  location ~ \.php$ {
      #try_files $uri =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass backend;
      fastcgi_index index.php;
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
Enter fullscreen mode Exit fullscreen mode

For doing the routing with the frontend, we can simply do proxy_pass http://frontend, but for our PHP-FPM backend, we need to do fastcgi_pass backend;


FROM nginx
COPY ./default.conf /etc/nginx/conf.d/default.conf
Enter fullscreen mode Exit fullscreen mode

PHP (Backend) Dockerfile:

FROM php:7.4-fpm

# Copy composer.lock and composer.json into the working directory
COPY composer.lock composer.json /var/www/html/

# Set working directory
WORKDIR /var/www/html/

# Install dependencies for the operating system software
RUN apt-get update && apt-get install -y \
    build-essential \
    libpng-dev \
    zip \
    vim \
    git \

# Install extensions for php
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install gd

# Install composer (php package manager)
RUN curl -sS | php -- --install-dir=/usr/local/bin --filename=composer

# Copy existing application directory contents to the working directory
COPY . /var/www/html

# Assign permissions of the working directory to the www-data user
RUN chown -R www-data:www-data \
    /var/www/html/storage \

# Expose port 9000 and start php-fpm server (for FastCGI Process Manager)
CMD ["php-fpm"]
Enter fullscreen mode Exit fullscreen mode

Frontend (Vue):

Notice that we are running 2 Nginx containers (the other one serves also as proxy, while this one is just for serving the frontend):


server {
  listen 3000;

  location / {
    root /app;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
Enter fullscreen mode Exit fullscreen mode


FROM node:16 as build-stage
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build

FROM nginx as production-stage
RUN mkdir /app
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build-stage /app/dist /app
Enter fullscreen mode Exit fullscreen mode

And finally the docker-compose.yml which I put inside the backend folder for simplicity:


version: "2.0"
  #PHP Service
      context: .
      dockerfile: Dockerfile
    container_name: backend
    restart: unless-stopped
    tty: true
      SERVICE_NAME: backend
      SERVICE_TAGS: dev
    working_dir: /var/www/html/
      - ./:/var/www/html/
      - ./php/laravel.ini:/usr/local/etc/php/conf.d/laravel.ini
      - app-network

    stdin_open: true
    container_name: frontend
      context: ../frontend-code
      dockerfile: Dockerfile
      - /app/node_modules
      - ../frontend-code:/var/www/html/
      - app-network

  #Nginx Service
      - backend
      - frontend
      context: ./nginx
      dockerfile: Dockerfile
    container_name: webserver
    restart: unless-stopped
    tty: true
      - "80:80"
      - app-network

#Docker Networks
    driver: bridge
Enter fullscreen mode Exit fullscreen mode

If there are things that can be improved with this setup or if you have questions, feel free to post a comment.

Top comments (7)

m0s4ysh3ll0 profile image
Moritz Büttner • Edited

Hello Philip! First of all: Thank you for this good article! It was exactly what I was looking for! :)
I was wondering if it is somehow possible to configure nginx to also allow api requests from outside the container network. When I 'docker exec' into the webserver container, I can call my laravel api with backend:9000/api/test, but from outside the container (eg. with Postman) I get 502 error back from nginx. I was hoping to do it like localhost/api/test, but no success so far.

I'm looking forward to your answer and thanks in advance!

Kind regards,

programmingdecoded profile image
Philip Perry

Hi Mo, Sorry for the late answer. Yes, localhost/api/test should work. Is there anything in the Docker logs of your container that could give you a clue as to what went wrong?

m0s4ysh3ll0 profile image
Moritz Büttner

I figured it out, just forgot to write it here in the comments... :) thank you!

jaaf profile image

Hello Phillip. Thank you very much for this article. It is close to what I am looking for.
Unfortunately when I visit the localhost I get a blank page.
Here is what I did.
I created a new laravel application with
laravel new dockertest
cd dockertest
I then created a vue app with
npm init vite vue
I renamed the vue folder to frontend-code and created a backend-code folder in which I put the laravel app.
I tested the backend with
php artisan serve
and the frontend with
npm install && npm run dev
Both worked fine. I was a bit surprised to see that the port for the frontend server was 5173 and not the 3000 I was accustomed to.
I stopped both servers.
Then I replicated the structure you define adding the files you provide.
I cded in backend-code and run
docker-compose up -d.
Visiting the localhost page
I had a blank page and only 4 requests done, the last one being for the favicon.ico
Image description
I did the same with a more advanced application and the result was roughly the same.
Could you help me?

codeperl profile image
mohammad ahsrafuddin ferdousi • Edited


Nicely written! I have a bit different scenario. If you can help me with that I will be glad.

I have one container for nuxt app. This "nuxt-app" is ssr runs in port 3001 and running behind nginx with "proxy_pass". This nginx container name is "nuxt-nginx". "nuxt-nginx" runs at port 443 at guest and from host port 4430. So, the url is

I have another container for laravel api. This "laravel-api" is running behind nginx too. This nginx container name is "laravel-api-nginx". "laravel-api-nginx" runs at port 443 at guest and from host port 443. So, the url is

From "nuxt-app", (which use nginx port 443 to run at port 3001 actually.) I am calling api ( with axios. it also use "auth-next" and "proxy" for axios. This is my gist for nuxt.config.js.

Application dockrized successfully. The nuxt app is running successfully too. But when I am trying to login via axios. It shows "axios: Network error"!

I am stuck here for last 3-5 days and can't move forward!

Any help is really appreciated!

homeynow profile image

Hello Philip,
i tried this one and i am getting this error. Can you help me?
Step 2/11 : COPY composer.lock composer.json /var/www/html/
COPY failed: file not found in build context or excluded by .dockerignore: stat composer.lock: file does not exist

thank you

dlgombert profile image
Daniel Gombert

Hay homeynow - this is because the file is copied over before composer install. In other words, you don't have a composer.lock file yet. There's probably a better way to do this, but for now on the host side, just create a file called composer.lock in your backend-code container. That will fix this.