Directus deployment on Elastic Beanstalk - apache2

I cloned Directus 8 from github. I run it in my local server. It worked fine without any problems.
Then I uploaded code to AWS Elastic Beanstalk (PHP, apache). but it showed 500 Internal Server Error.
error log: /var/www/html/directus/public/.htaccess: <IfModule not allowed here
I added .ebextensions/setup.config file to my root folder, like this.
files:
"/etc/httpd/conf.d/enable_mod_rewrite.conf":
mode: "644"
owner: root
group: root
content: |
AllowOverride All
but my Beanstalk said Unsuccessful command execution on instance id(s) 'i-0f6...'. Aborting the operation. and went to degrading state.
How to fix this?

This answer is for Directus 8 (PHP)
Tried almost all ways of apache settings using .ebextensions and .platform nothing worked.
Then tried NGINX with custom .platform configs. It worked. Answering the steps which I did, may be helpful to someone else, who has the same problem
Directus docs has some configs for NGINEX, go through it
create nginex.conf file under .platform/nginx folder
we are going to replace existing nginex.conf inside the beanstalk. copy existing nginex.conf using ssh to ec2 instance and add the custom configs mentioned in the docs and paste it to our newly created .platform/nginx/nginex.conf
below is my custom .platform/nginx/nginex.conf
user nginx;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 32136;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
include conf.d/*.conf;
map $http_upgrade $connection_upgrade {
default "upgrade";
}
server {
listen 80 default_server;
location / {
try_files $uri $uri/ /index.php?$args;
}
location /admin {
try_files $uri $uri/ /admin/index.html?$args;
}
location /thumbnail {
try_files $uri $uri/ /thumbnail/index.php?$args;
}
# Deny direct access to php files in extensions
location /extensions/.+\.php$ {
deny all;
}
# All uploads files (originals) cached for a year
location ~* /uploads/([^/]+)/originals/(.*) {
add_header Cache-Control "max-age=31536000";
}
# Serve php, html and cgi files as text file
location ~* /uploads/.*\.(php|phps|php5|htm|shtml|xhtml|cgi.+)?$ {
add_header Content-Type text/plain;
}
# Deny access to any file starting with .ht,
# including .htaccess and .htpasswd
location ~ /\.ht {
deny all;
}
# pass PHP scripts to FastCGI server
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm/www.sock;
fastcgi_index index.php;
include /etc/nginx/fastcgi.conf;
}
access_log /var/log/nginx/access.log main;
# Include the Elastic Beanstalk generated locations
include conf.d/elasticbeanstalk/*.conf;
}
}
done, when we uploading it, beanstalk will automatically replace our custom nginex.conf with existing nginex.conf. (note: we can add the changes only instead of replacing, but it didn't work at the time I tried)

Related

Dockerized NGINX returns 404 instead of static React files

I use Docker and NGINX to serve SPA built with React. Everything was fine until I added some caching inspired by this gist. Currently, NGINX returns 404 for all files in static folder.
This is how NGINX config looks like:
server {
listen 80;
location / {
root /usr/share/nginx/html/;
include /etc/nginx/mime.types;
try_files $uri $uri/ /index.html;
}
# These two location directives cause the issue, if remove them it will be running fine
location ~* \.(?:jpg|jpeg|gif|png|ico|svg)$ {
expires 7d;
add_header Cache-Control "public";
}
location ~* \.(?:css|js)$ {
add_header Cache-Control "no-cache, public, must-revalidate, proxy-revalidate";
}
}
This is what error messages look like, there is etc folder prepended to the path which is invalid:
2022/09/28 09:58:46 [error] 11#11: *4 open() "/etc/nginx/html/static/css/main.45f86988.css" failed (2: No such file or directory), client: 172.17.0.1, server: , request: "GET /static/css/main.45f86988.css HTTP/1.1", host: "localhost:3244", referrer: "http://localhost:3244/"
Files are definitely stored within the container, but again without that etc folder:
/usr/share/nginx/html/static # find
.
./css
./css/main.45f86988.css
./css/main.45f86988.css.map
./js
./js/496.a53b338e.chunk.js
./js/NotFoundComponent.af4d0ff3.chunk.js
./js/main.adbec619.js
./js/main.adbec619.js.map
./js/285.f49f8f0e.chunk.js
./js/MapComponent.3d89394e.chunk.js
./js/MapComponent.3d89394e.chunk.js.map
./js/NotFoundComponent.af4d0ff3.chunk.js.map
./js/DemoContainer.7bc357cb.chunk.js.map
./js/496.a53b338e.chunk.js.map
./js/main.adbec619.js.LICENSE.txt
./js/285.f49f8f0e.chunk.js.map
./js/DemoContainer.7bc357cb.chunk.js
/usr/share/nginx/html/static #
P.S. I haven't used NGINX before and I'm sorry if the answer is obvious
It looks like your files are in /usr/share/nginx/html/static folder, but nginx is trying to read them from /etc/nginx/html/. I would recommend moving the root /usr/share/nginx/html/ line to the server block.
Something like that:
server {
listen 80;
root /usr/share/nginx/html/;
...
}

Create internal connection between React and Laravel in Docker containers on server

I am using a React app as frontend and a Laravel app for backend. These two are connected with each other through Laravel Sanctum APIs. The whole environment is deployed on the server using Docker, frontend & backend being separate containers, but connected with network: someNetwork
The API call is done from the frontend using the URL HTTP://myserverip:8000 - this is working, but I would like to close the 8000 port (externally) and just keep open the 3000 port where the frontend is working. Now when I'm closing the 8000 port (with firewall), and trying to make API request from frontend I get a network error.
The question is, how to make the API request internally so I can keep only 3000 open, do I need some kind of redirection inside the .conf file of the nginx? This is my .conf file:
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/public;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app: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 / {
try_files $uri $uri/ /index.php?$query_string;
gzip_static on;
}
}
Thanks, any hint would be appreciated.
What you are trying to do will never work.
ReactJS (I guess thats what you mean by ReactApp) should be "build" before used in production. The result will be a build folder with a bunch of static files.
These files can be deployed / serverd using NGINX. The API-Calls from ReactJS (your Frontend App) will always come from outside of your network as the client / customer will not be part of your Docker NAT network (I guess).
I would use NGINX as a Webserver for your ReactApp (ReactJS Build) as well as a reverse Proxy / Proxy for your Laravel Backend.
Something like:
server {
listen 443 ssl;
server_name example.com
.....
root /path/to/your/reactapp/static/files;
location / {
try_files $uri /index.html;
}
}
server {
listen 443 ssl;
server_name api.example.com;
...all the laravel PHP config here
}
if you can not or want not create a subdomain for your API use a location
server {
listen 443 ssl;
server_name example.com
.....
root /path/to/your/reactapp/static/files;
location / {
try_files $uri /index.html;
}
location /api/ {
Do your Laravel config here (use nested locations for handling the php files)
Or do a `proxy_pass` and configure an internal server (listen `8000`) and do not expose it.
}
}

How to set up nginx config for a React.js app deployed on AWS ECS with path-based routing load balancer

I have an application which consists of two containers:
a backend node.js server on express.js, referred to as 'app-server'
a front-end react.js client based on create-react-app, referred to as 'app-client'. This one uses an nginx server to set up reverse proxy for /api requests to the application - like this post describes
Both are dockerized and deployed on AWS ECS Fargate and are supposed to be hosted on the same domain example.com, just different paths, respectively /app-server and app-client. So the users would access the app via https://example.com/app-client. In the future we would like to host more apps on the same domain using path based routing.
To achieve that we have defined a rule on the Application Load Balancer listener on EC2 which looks like this:
IF
- Path is: /app-client*
- Host is: example.com
THEN
- Forward to
- app-client-service-alb-h: 1 (100%)
- Group-level stickiness: Off
Also tested - Path is: /app-client, without the * at the end.
I managed to adjust the backend express server to work with this scenario but I'm struggling to make the React.js app work with the path forwarding - it just shows a blank page (worked without a problem when it was hosted directly on a domain, let's say http://app-client.com).
My guess is it has something to do with the nginx config because the request URL's are correct but there are just no .html, .js and .css files there.
Dockerfile looks like this:
FROM node:11.5.0 as builder
WORKDIR /usr/src/app
ADD ./ /usr/src/app
RUN npm install && \
npm run build
# ------------------------------------------------------
# Production Build
# ------------------------------------------------------
FROM nginx:1.16.0-alpine
COPY --from=builder /usr/src/app/build/ /usr/share/nginx/html
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Nginx config is set up this way:
server {
listen 80;
server_name example.com;
location /api {
proxy_pass https://example.com/app-server;
proxy_pass_request_headers on;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
React app's package.json file was adjusted by adding homepage setting:
"homepage": "/app-client"
Also tried with "homepage": "https://example.com/app-client". In both scenarios requested paths look correct, for example:
https://example.com/app-client/static/js/main.32859df6.chunk.js
The problem is that there is nothing found under this address, the page is blank. That's why I am assuming that nginx config needs to be adjusted to provide the file from correct location but have no idea what to adjust (I did also test removing the "homepage" from package.json but that also didn't solve it.).
I tried changing the location to location /app-client { or location ^~ /app-client { but that didn't work:
location /app-client {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
I blindly followed many other solutions, for example:
Nginx Meets Amazon ECS: Hosting Multiple Back-End Services Using a Single Load Balancer
Based on this config
None of them fixed the problem and I'm a rookie in that area so I'm stuck... Please help :(
------- Edited -------
The issue is solved and I'm posting the answer in case someone else finds it helpful.
The Nginx config should look like this, with appropriate rewrite defined:
server {
listen 80;
# All files should be at this directory; put it above location, otherwise it was looking in a wrong directory somewhere in `/etc/...`
root /usr/share/nginx/html;
# Prefix app-client -> rewrite
location /app-client {
rewrite ^/app-client(?:/(.*))?$ /$1;
}
# proxy for backend server /api requests
location /api {
# the ending `/api` part depends on whether your server routes also start with `/api` or not, mine do hence it was required
proxy_pass https://example.com/app-server/api;
proxy_pass_request_headers on;
}
location / {
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
The issue is solved and I'm posting the answer in case someone else finds it helpful.
The Nginx config should look like this, with appropriate rewrite defined:
server {
listen 80;
# All files should be at this directory; put it above location, otherwise it was looking in a wrong directory somewhere in `/etc/...`
root /usr/share/nginx/html;
# Prefix app-client -> rewrite
location /app-client {
rewrite ^/app-client(?:/(.*))?$ /$1;
}
# proxy for backend server /api requests
location /api {
# the ending `/api` part depends on whether your server routes also start with `/api` or not, mine do hence it was required
proxy_pass https://example.com/app-server/api;
proxy_pass_request_headers on;
}
location / {
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
Here is an example of my microservices application hosted on AWS with ALB & ECS.
ECS has multiple backend services, react app static files being served from frontend container service which is NGINX reverse proxy.
NGINX_ALB is the ALB DNS name stored in env variable inside container during Dockerfile build.
Gets substituted into nginx config using:
CMD ["/bin/sh", "-c", "export NGINX_ALB && envsubst '$$NGINX_ALB' < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/nginx.conf && nginx -g 'daemon off;'"]
upstream alb {
least_conn;
server ${NGINX_ALB}:80 max_fails=3;
}
server {
# ref https://www.veggiespam.com/bad-headers/
proxy_hide_header Server;
proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNetMvc-Version;
proxy_hide_header X-AspNet-Version;
proxy_hide_header X-Drupal-Cache;
proxy_hide_header X-Drupal-Dynamic-Cache;
proxy_hide_header X-Generator;
proxy_hide_header X-Runtime;
proxy_hide_header X-Rack-Cache;
# proxy_set_headers moved to server directive allowing them to be referenced by all locations
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
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;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 300s;
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /auth/ {
proxy_pass http://alb;
proxy_redirect off;
}
location /api/sigma {
proxy_pass http://alb;
proxy_redirect off;
}
location /api/ {
proxy_pass http://alb;
proxy_redirect off;
}
location /db {
proxy_pass http://alb;
proxy_redirect off;
}
location /scheduler {
proxy_pass http://alb;
proxy_redirect off;
}
location /validator {
proxy_pass http://alb;
proxy_redirect off;
}
location /alarm/ {
proxy_pass http://alb;
proxy_redirect off;
}
location /reporter {
proxy_pass http://alb;
proxy_redirect off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

Deploy Laravel and React spa

How can I deploy these two together, I don't like the Laravel React preset, I want to separate both, bundle the React app and deploy them together with any web server (apache, nginx...)
EDIT
This is my config for Laravel, but it isn't loading the routes
server {
listen 8000;
server_name 127.0.0.1
root "..\..\Proyecto\Backend\JWT\public";
add_header 'Access-Control-Allow-Origin' '*';
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
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$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
You can run them separately using nginx
you run each on separate ports and use methods (POST/GET) to push/get data
use pm2 (http://pm2.keymetrics.io/) for running React (I recommend it because you can monitor the activity of the react app and if you want to do maintenance you can stop the current app process and run a "under maintenance" app process)
you can read more about running laravel on nginx here (https://www.digitalocean.com/community/tutorials/how-to-deploy-a-laravel-application-with-nginx-on-ubuntu-16-04)
as for running react without pm2, you have to build the project yarn build and tell nginx that the file you want to load is the index.html inside of the build file
assuming that you are using an ubuntu server and you uploaded your code to github or gitlab
server {
listen 50;
root /var/www/[Your repo name]/build;
server_name [your.domain.com] [your other domain if you want to];
index index.html;
location / {
try_files $uri /index.html;
}
}
you write this inside of your nginx configuration along with the laravel configuration on a separate port
hope my answer helped a bit
This was proving to be very tricky and it took me at least 3 days to put everything together. Here is what you have to do.
Run
npm run build in the react project.
Copy the contents of the build folder to the server
scp react_project/build/* <server name or ip>:/var/www/html/react
Change the ownership of the project folders to the user www-data or add your user id to the group www-data.
Now. set up the Laravel project in a different directory (in /var/www/html/laravel, for example).
Set up the database, environment variables.
Run
php artisan key:generate
php artisan config:clear
php artisan config:cache
Now, proceed with nginx configuration. Create 2 configs for react and laravel projects as given below. Make sure that the listen ports are different for both projects.
Create configuration files for react and laravel projects under /etc/nginx/sites-available
Create symlinks to the created configs under /etc/nginx/sites-enabled as given below
sudo ln -s /etc/nginx/sites-available/react_conf /etc/nginx/sites-enabled/react_conf
sudo ln -s /etc/nginx/sites-available/laravel_conf /etc/nginx/sites-enabled/laravel_conf
And for the contents,
react_conf:
server {
listen 80;
server_name <server_ip or hostname>;
charset utf-8;
root /var/www/html/react;
index index.html index.htm;
# Always serve index.html for any request
location / {
root /var/www/html/react;
try_files $uri /index.html;
}
error_log /var/log/nginx/react-app-error.log;
access_log /var/log/nginx/react-app-access.log;
}
laravel_conf:
server {
listen 90;
server_name <server ip or hostname>;
charset utf-8;
root /var/www/html/laravel/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php index.html index.htm;
# Always serve index.html for any request
location /api {
try_files $uri $uri/ /index.php?$query_string;
}
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$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
error_log /var/log/nginx/laravel-app-error.log;
access_log /var/log/nginx/laravel-app-access.log;
}
Now, delete the default config present in /etc/nginx/sites-enabled
Also, verify that /etc/nginx/nginx.conf contains the following include directive where the server configs are expected(under http)
include /etc/nginx/sites-enabled/*;
Verify that the config is fine by running
sudo nginx -t
Restart the server
sudo service nginx restart
Now, you should be up and running.
You can approach it by two ways .
First one is when the you are creating react-app in different folder than the laravel project folder . In such case just deploy laravel app and react app in two different url .
The second condition is when the react-app is inside the laravel app . In such case build the react project and put the dist folder in views folder of the laravel project . So in routes/web.php add this
//Used for handling the html file of react project
View::addExtension('html', 'php');
Route::get('/{any}', function () {
//path to dist folder index.html inside the views directory
return view('build/index');
})->where('any', '.*');
Laravel will not server the required js and css file from inside the views folder . So you need copy and paste all the content of the dist folder to public folder of the laravel project . No need to copy paste index.html file but other file need to placed in the pubic folder .
After that visit the root url of the laravel project in the browser the react app should be working

Nginx single application config

I'm writing an AngularJS single page application using nginx.
I just switched from apache to nginx, but I cant make my config file working.
I'm trying to rewrite everything to index.html to let Angular do the routing.
My nginx.conf is as follow:
server {
index index.html;
location / {
expires -1;
add_header Pragma "no-cache";
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
try_files $uri $uri/ /index.html;
}
}
Is it possible to have my nginx.conf file in the project root like my .htaccess did?
You dont want nginx.conf in the project root and its not necessary. Also, you don't want direct changes to nginx.conf, you will instead want specific files for different websites in /etc/nginx/sites-available which you enable with a ln in /etc/nginx/sites-enabled.
As far as the config:
server {
root /var/www/mysite/; #or whereever your site files are
index index.html;
location /{
try_files $uri $uri/ =404;
}
}
You are missing the root portion which tells nginx where the site is located.

Resources