Search code examples
phplaraveldockernginxdocker-compose

Looping problem when trying to login on Laravel 10


Good morning

Currently I have an application running within AWS through the ElasticBeanstalk infrastructure, this application is made with the Laravel 10 tool and has nginx as a server.

My mission is to transform this EB application into a docker solution using AWS ECS, I have already developed several different images and different ways of implementing the system, but I have reached a point where every time I try to log into my system, it presents a error 419, which is directly related to the CRSF Token. To continue my tests, I added the login page to the exception of this CSRF Token, and from that, every time I try to log into my system it loops to the login page again.

Login done > http://localhost:8000/dashboard > http://localhost:8000/login > http://localhost:8000/

As I work exclusively with infrastructure and did not participate in the initial creation of the project, I don't know exactly what information to provide, but I can pass on what I changed to get to my login page. I currently have the following tests carried out:

  • I tested running the application in two different containers, one for the application itself and the other for nginx, which is the most recommended thing to do;

  • I tested setting up a single container that has the application and nginx in the same container, not being the best option for production but made for testing purposes;

  • I test locally with a database running on my local machine, so the tests done on my machine have the 'host' configuration within docker-compose, when I test within the ECS environment I use an endpoint from my VPC

As I am adapting a project initially developed for ElasticBeanstalk, the Nginx part is very simple, many of the necessary things were automated by EB

To be simpler, I'll tell you how I'm doing it using the concept of just 1 container, since in all the methods I reached the same point:

Dockerfile:

    FROM php:8.1-fpm

    #  set your user name, ex: user=bernardo
    ARG USER=laravel
    ARG PASS=laravel
    ARG uid=1000
    RUN useradd -m -s /bin/bash $USER && echo "$USER:$PASS" | chpasswd
    ARG COMPOSER_ALLOW_SUPERUSER=1

    ENV DEBIAN_FRONTEND noninteractive

    # Install Programs
    RUN apt-get update \ 
        && apt-get install -y curl \        
        libpng-dev \
        libonig-dev \
        libxml2-dev \
        wget \
        curl \
        gnupg2 \
        software-properties-common \
        apt-transport-https \
        ca-certificates \
        lsb-release \
        zip \
        unzip \
        nodejs \
        npm \
        redis \
        nano \
        nginx \
        inetutils-ping \
        libicu-dev \
        zlib1g-dev \
        libzip-dev \
        libcurl4-openssl-dev

    # PHP_CPPFLAGS are used by the docker-php-ext-* scripts
    ENV PHP_CPPFLAGS="$PHP_CPPFLAGS -std=c++11"

    RUN docker-php-ext-install xml gd mbstring zip curl mysqli soap bcmath exif pdo pdo_mysql

    RUN pecl install mongodb && docker-php-ext-enable mongodb

    # Clear cache
    RUN apt-get clean && rm -rf /var/lib/apt/lists/*

    # Get latest Composer
    COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

    # Create system user to run Composer and Artisan Commands
    #RUN useradd -G www-data,root -u $uid -d /home/$USER $USER
    RUN mkdir -p /home/$USER/.composer && \
        chown -R $USER:$USER /home/$USER

    # Set working directory
    WORKDIR /var/app/current

    # Copies the .env file into the container
    COPY .env.example .env
    # COPY .env.dev .env

    # Copy Laravel application files
    COPY . /var/app/current

    # Copy custom configurations PHP
    COPY docker/php/custom.ini /etc/php/conf.d/custom.ini
    COPY docker/nginx/laravel.conf /etc/nginx/conf.d/laravel.conf
    COPY entrypoint.sh /etc/entrypoint.sh

    # Runs composer install and npm install to start the project
    RUN composer install && npm install

    RUN touch /var/app/current/storage/logs/laravel.log
    RUN chmod -R gu+w storage/
    RUN chmod -R guo+w storage/
    RUN chmod -R 777 bootstrap/cache/
    RUN chown ${USER}:${USER} -R ./storage
    RUN chmod +x /etc/entrypoint.sh

    # Switches to user Laravel
    USER $user

    EXPOSE 9000
    EXPOSE 8000
    # EXPOSE 80
    EXPOSE 3306

    ENTRYPOINT ["/etc/entrypoint.sh"]

Docker-compose:

    version: "3.7"

    services:
        laravel-solo:
        stdin_open: true
        tty: true
        container_name: app
        ports:
            - 8000:8000
        network_mode: host
        image: laravel-solo
        volumes:
        - ./:/var/app/current
        - ./docker/nginx/laravel.conf:/etc/nginx/sites-enabled/default
        - ./docker/nginx/laravel.conf:/etc/nginx/conf.d/laravel.conf

.conf file:

    server {
        listen 8000;
        listen [::]:8000;
        server_name localhost;
        root /var/app/current/public;
        index index.php;

        # Security headers
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always;
        add_header X-Content-Type-Options nosniff always;
        add_header X-XSS-Protection "1;mode=block" always;

        client_max_body_size 100M;

        # Redirect to HTTPS
        if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri;
        }

        add_header X-Frame-Options "SAMEORIGIN";
        add_header X-Content-Type-Options "nosniff";
     
        charset utf-8;
     
        location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
        }
     
        # location = /favicon.ico { access_log off; log_not_found off; }
        # location = /robots.txt  { access_log off; log_not_found off; }
     
        error_page 404 /index.php;
     
        location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass localhost:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        }
     
        location ~ /\.(?!well-known).* {
        deny all;
        }


    }

If I'm missing any more details that you need, please let me know, as I don't know the PHP/Laravel part very well.

1st Redirect 2nd Redirect


Solution

  • Just a quick update on my problem:

    I decided to take a step back and recreate my Dockerfile once more, and i found this image: wyveo/nginx-php-fpm.

    I used it to create my environment and i was not only able to surpass the looping error but also shrink significantly my docker image. This image gave me a complete environment with Nginx and PHP-FPM that are already set up for Laravel projects. It also facilitate to upload to ECS, since it hasn't many layers of complexicity anymore like volumes, etc..

    Here's the DockerFile image:

    FROM wyveo/nginx-php-fpm:latest
    
    # Environment variables
    ENV DEBIAN_FRONTEND noninteractive
    
    # Set working directory
    WORKDIR /var/app/current
    
    # Copy Laravel application files
    RUN rm -rf /usr/share/nginx/html
    
    # Copy project files
    COPY . /var/app/current
    
    # Copies the entrypoint script into the container
    COPY entrypoint.sh /etc/entrypoint.sh
    
    # Copies the NGINX .conf files into the container
    COPY ./.docker/nginx/ /etc/nginx/conf.d/
    
    # Copies the .env file into the container
    COPY .env.dev .env
    
    # Create a symbolic link for the /public folder
    RUN ln -s public html
    RUN chmod +x /etc/entrypoint.sh
    

    This image has by default the /usr/share/nginx directory as root, but you're able to change it for anoter one with no problems, you just need to adapt a custom .conf file and upload it like i did on the Dockerfile

    My default.conf file

    server {
        listen   80; ## listen for ipv4; this line is default and implied
        listen   [::]:80 default ipv6only=on; ## listen for ipv6
    
        root /var/app/current/public;
        index index.php index.html index.htm;
    
        # Make site accessible from http://localhost/
        # server_name _;
        server_name localhost;
    
        # Disable sendfile as per https://docs.vagrantup.com/v2/synced-folders/virtualbox.html
        sendfile off;
    
        # Security - Hide nginx version number in error pages and Server header
        server_tokens off;
    
        # Add stdout logging
        error_log /dev/stdout info;
        access_log /dev/stdout;
    
        # reduce the data that needs to be sent over network
        gzip on;
        gzip_min_length 10240;
        gzip_proxied expired no-cache no-store private auth;
        gzip_types text/plain text/css text/xml application/json text/javascript application/x-javascript application/xml;
        gzip_disable "MSIE [1-6]\.";
    
        # location / {
        #     # First attempt to serve request as file, then
        #     # as directory, then fall back to index.php
        #     try_files $uri $uri/ /index.php?$query_string $uri/index.html;
        # }
    
        location / {
    
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
        }
    
        # redirect server error pages to the static page /50x.html
        #
        error_page 404 /index.php;
        location = /50x.html {
            root   /var/app/current/public;
        }
    
        # Security headers
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" always;
        add_header X-Content-Type-Options nosniff always;
        add_header X-XSS-Protection "1;mode=block" always;
    
        client_max_body_size 100M;
    
        # Redirect to HTTPS
        if ($http_x_forwarded_proto = "http") {
        return 301 https://$host$request_uri;
        }
    
        # pass the PHP scripts to FastCGI server listening on socket
        #
        location ~ \.php$ {
            try_files $uri $uri/ /index.php?$query_string;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/run/php/php8.2-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    
            location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
                    expires           5d;
            }
    
        # deny access to . files, for security
        #
        location ~ /\. {
                log_not_found off;
                deny all;
        }
    
    }