'cors issue in post request while deploying laravel inside docker

I have a laravel app which is running behind nginx proxy manager. The laravel app is running inside a docker container and nuxt frontend is also running inside another docker container. Laravel is using fortify, sanctum packages for authentication and session validation.

The issue is that when i try to login using a fake user. then all preflight request, get request works perfectly fine. but when i try to make a post request for login, then it seems to work perfectly fine. as response status is 200 as in header. but says that Access Control Allow Origin header is missing, which causes no response to show up.

what i am missing. where is the issue? this seems to be a common problem.

methods to reproduce.

  • try to login with any email id & password, which ideally should throw 422 error along with validation error messages. but instead comes 200 with no script/ cors error

I have already tried.

  • i added following in my laravel nginx deployment configuration which seems to solve post problem but then when user details is fetched using /api/user(default sanctum user). then 401 issue comes. this doesn't seem to be a valid answer. (
    location / {
        try_files $uri $uri/ /index.php?$query_string;

        if ( $request_method = POST ) {          
            add_header 'Access-Control-Allow-Origin' 'https://codalay.in';         
            add_header 'Access-Control-Allow-Credentials' 'true'; 
        }
    }
  • another way i tried is i added following code in api.codalay.in's reverse proxy nginx configuration . then cors error changes
# custom headers required for cors issues for laravel.
add_header Access-Control-Allow-Origin origin;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Expose-Headers Content-Length;
add_header Access-Control-Allow-Headers Range;

and throws

Reason: CORS header 'Access-Control-Allow-Origin' does not match 'https://codalay.in'

I am trying to fix this issue from 10 days. please help

Edit 1: added my configurations files backend docker-compose.yml

version: '3'

networks:
  laravel:
  nginx_reverse_proxy:
    external: true

services:
  codalay-nginx:
    image: nginx:stable-alpine
    container_name: nginx-codalay
    ports:
      - "8080:80"
    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - codalay-php
      - codalay-mysql
    networks:
      - laravel
      - nginx_reverse_proxy

  codalay-mysql:
    image: mysql:8
    container_name: mysql
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: codalay
      MYSQL_USER: rex
      MYSQL_PASSWORD: 'somerandomstring'
      MYSQL_ROOT_PASSWORD: 'somerandomstring'
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    networks:
      - laravel
      - nginx_reverse_proxy

  codalay-php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php
    volumes:
      - ./src:/var/www/html
    ports:
      - "9000:9000"
    networks:
      - laravel
      - nginx_reverse_proxy

  composer:
    image: composer:latest
    container_name: composer
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
    depends_on:
      - codalay-php
    networks:
      - laravel
      - nginx_reverse_proxy

  npm:
    image: node:16
    container_name: npm
    volumes:
      - ./src:/var/www/html
    working_dir: /var/www/html
    entrypoint: [ 'npm' ]
    networks:
      - nginx_reverse_proxy

  codalay-artisan:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: artisan
    volumes:
      - ./src:/var/www/html
    depends_on:
      - codalay-mysql
    working_dir: /var/www/html
    entrypoint: [ 'php', '/var/www/html/artisan' ]
    networks:
      - laravel
      - nginx_reverse_proxy

backend nginx configuration:

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

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

        # if ( $request_method = POST ) {          
            add_header 'Access-Control-Allow-Origin' 'https://codalay.in';         
            add_header 'Access-Control-Allow-Credentials' 'true'; 
        # }
    }

    location ~ \.php$ {
        fastcgi_read_timeout 240;
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }


}

reverse-proxy nginx configuration

# ------------------------------------------------------------
# api.codalay.in
# ------------------------------------------------------------


server {
  set $forward_scheme http;
  set $server         "nginx-codalay";
  set $port           80;

  listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443 ssl http2;


  server_name api.codalay.in;


  # Let's Encrypt SSL
  include conf.d/include/letsencrypt-acme-challenge.conf;
  include conf.d/include/ssl-ciphers.conf;
  ssl_certificate /etc/letsencrypt/live/npm-4/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/npm-4/privkey.pem;




# Asset Caching
  include conf.d/include/assets.conf;


  # Block Exploits
  include conf.d/include/block-exploits.conf;



  # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
  add_header Strict-Transport-Security "max-age=63072000;includeSubDomains; preload" always;
  add_header Referrer-Policy strict-origin-when-cross-origin; 
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Frame-Options SAMEORIGIN;
  add_header Content-Security-Policy upgrade-insecure-requests;
  add_header Permissions-Policy interest-cohort=();
  add_header Expect-CT 'enforce; max-age=604800';
  more_set_headers 'Server: Proxy';
  more_clear_headers 'X-Powered-By';




# custom headers required for cors issues for laravel.
# add_header Access-Control-Allow-Origin origin;
# add_header Access-Control-Max-Age 3600;
# add_header Access-Control-Expose-Headers Content-Length;
# add_header Access-Control-Allow-Headers Range;

# proxy_redirect                      off;
# proxy_set_header X-Real-IP          $remote_addr;
# proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto  $scheme;
# proxy_read_timeout                  3600;
# proxy_connect_timeout               3600;

# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection 'upgrade';
# proxy_set_header Host $host;
# proxy_cache_bypass $http_upgrade;


    # Force SSL
    include conf.d/include/force-ssl.conf;




proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;


  access_log /data/logs/proxy-host-11_access.log proxy;
  error_log /data/logs/proxy-host-11_error.log warn;







  location / {

    



  # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
  add_header Strict-Transport-Security "max-age=63072000;includeSubDomains; preload" always;
  add_header Referrer-Policy strict-origin-when-cross-origin; 
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Frame-Options SAMEORIGIN;
  add_header Content-Security-Policy upgrade-insecure-requests;
  add_header Permissions-Policy interest-cohort=();
  add_header Expect-CT 'enforce; max-age=604800';
  more_set_headers 'Server: Proxy';
  more_clear_headers 'X-Powered-By';




# custom headers required for cors issues for laravel.
# add_header Access-Control-Allow-Origin origin;
# add_header Access-Control-Max-Age 3600;
# add_header Access-Control-Expose-Headers Content-Length;
# add_header Access-Control-Allow-Headers Range;

# proxy_redirect                      off;
# proxy_set_header X-Real-IP          $remote_addr;
# proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto  $scheme;
# proxy_read_timeout                  3600;
# proxy_connect_timeout               3600;

# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection 'upgrade';
# proxy_set_header Host $host;
# proxy_cache_bypass $http_upgrade;


    
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_http_version 1.1;
    

    # Proxy!
    include conf.d/include/proxy.conf;
  }


  # Custom
  include /data/nginx/custom/server_proxy[.]conf;
}


edit 2: I am using laravel 9



Solution 1:[1]

Hello Here is my laravel conf for nginx.

server {
    listen 80 ;
    listen [::]:80 ;
    root /pathtoproject/public;
    index index.php index.html index.htm index.nginx-debian.html;
    server_name domainname;
    
    return 301 https://$host$request_uri;


}


server {
    listen 443 ssl http2;
    #listen [::]:443 ssl;

    ssl_certificate /var/www/keys/bundle.crt;
    ssl_certificate_key /var/www/keys/*.domain.key;



    root /pathtoproject/public;
    index index.php index.html index.htm index.nginx-debian.html;
    server_name domainname.com;
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";
    charset utf-8;
    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # With php-fpm (or other unix sockets):
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 1800;
        # With php-cgi (or other tcp sockets):
        #fastcgi_pass 127.0.0.1:9000;
         proxy_read_timeout 5m; 

    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
    
}

Here is my anguler side script for working setup. use api access as domain.com/api/

server {
    listen 80;
    listen [::]:80;
    index index.html index.htm index.nginx-debian.html;

    server_name maindomain.com;
    return 301 https://$host$request_uri;

}
server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    index index.html index.htm index.nginx-debian.html;

    ssl_certificate /var/www/keys/bundle.crt;
    ssl_certificate_key /var/www/keys/*.domain.key;


    server_name maindomain.com;

    location / {
        proxy_pass http://127.0.0.1:4400;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
    location ~ /\.(?!well-known).* {
        deny all;
    }
    
    location /api/ {
        proxy_pass https://api.domain.com;
    }
    location /storage/ {
        proxy_pass https://api.domain.com;
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shashikant Chauhan