Skip to content

Instantly share code, notes, and snippets.

@henhan
Last active April 15, 2024 02:31
Show Gist options
  • Star 53 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save henhan/2943013c9064606425b0ee5bb1ca8c99 to your computer and use it in GitHub Desktop.
Save henhan/2943013c9064606425b0ee5bb1ca8c99 to your computer and use it in GitHub Desktop.
Extend and override nginx config for Elastic Beanstalk Amazon Linux 2

Extend and override nginx config for Elastic Beanstalk Amazon Linux 2

Documentation on how to override or extend the default nginx config on Elastic Beanstalk running om Amazon Linux 2. Correct as of 2021-08-01. Also see the general documentation on how to extend linux servers.

All references to placing files refer to putting a file at this location in your application bundle. You should never modify a file directly at your Elastic Beanstalk server by ssh:ing to the server, since such a change will be wiped whenever your servers autoscale or if you rebuild your application completely.

Adding a new location block

The easiest extension is to add a new location block to the main server block. This can be done by placing a .conf file with a server block in the folder .platform/nginx/conf.d/elasticbeanstalk. Any such file is automatically included in the main server block.

Overriding the default location

The default location block is most easily overridden by placing a file in the bundle at the location .platform/nginx/conf.d/elasticbeanstalk/00_application.conf. This will simply replace the default block provided by elastic beanstalk.

The default block looks like this (for node.js code - 2021-07-25 - other languages might run on a different port):

location / {
    proxy_pass          http://127.0.0.1:8080;
    proxy_http_version  1.1;

    proxy_set_header    Connection          $connection_upgrade;
    proxy_set_header    Upgrade             $http_upgrade;
    proxy_set_header    Host                $host;
    proxy_set_header    X-Real-IP           $remote_addr;
    proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
}

Forcing HTTPS

(Note that it might be a better idea to let the application load balancer handle this by redirecting traffic on port 80 to port 443 directly: https://aws.amazon.com/premiumsupport/knowledge-center/elb-redirect-http-to-https-using-alb/).

HTTPS can be forced by adding the following to the location block (note that it allows the health checker to use HTTP):

set $redirect 0;
if ($http_x_forwarded_proto != "https") {
    set $redirect 1;
}
if ($http_user_agent ~* "ELB-HealthChecker") {
    set $redirect 0;
}
if ($redirect = 1) {
    return 301 https://$host$request_uri;
}

Using basic auth

Basic auth can be activated by adding the following to the location block:

auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;

Note that you will then have to write the content to the .htpasswd file somehow. This can either be done by placing a files block in a config file in the .ebextensions folder (see documentation), or by running some kind of script to write the file. Such a script should be an executable file placed in either .platform/hooks/predeploy or .platform/confighooks/predeploy depending on how the content for the .htpasswd file is generated.

If you want to pass the auth basic credentials to the backend, add this as well:

proxy_set_header    Authorization       $http_authorization;

It will then be set as Authorization header in the backend. The content of this header will be Basic followed by the string username:password encoded as Base64.

Making basic auth work with health check.

To make the health check work with basic auth, you can set up a separate location block that does not require basic auth. Don't give this path access to any sensitive information, only to a basic healt check. Here's an example that allows the health check to access /elb-status, which is then passed on to a status route in the application:

location /elb-status {
    proxy_pass          http://127.0.0.1:8080/status;
}

Extending nginx configuration

The default nginx config will load any config file ending with .conf and placed in .platform/nginx/conf.d. You can use this to create new server blocks. This is the way to go if you need to do more than extend the default server block. If you create new server blocks you will have to check how nginx will prioritize the traffic. See https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms.

Overriding the default nginx configuration

To get complete control of the nginx configuration, it is possible to override the whole config. This is done by placing a full nginx configuration as .platform/nginx/nginx.conf. Only do this if you have to, since you will have to manually check if there is any changes to the default config for new releases to make sure that your configuration is still valid.

If you decide to override the full config, it is a good idea to include the content of the file found in /etc/nginx/conf.d/elasticbeanstalk/health.conf to get the health checking config as well (this also goes for new server blocks).

Default nginx configuration for reference

The following is the current nginx config used for node.js applications (as of 2021-07-25). It is mainly here for reference. You should ssh to your instance and check the currrent configuration to make sure that you're manipulating the latest version.

# Elastic Beanstalk Nginx Configuration File

user                    nginx;
error_log               /var/log/nginx/error.log warn;
pid                     /var/run/nginx.pid;
worker_processes        auto;
worker_rlimit_nofile    32633;

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;
        access_log    /var/log/nginx/access.log main;

        client_header_timeout 60;
        client_body_timeout   60;
        keepalive_timeout     60;
        gzip                  off;
        gzip_comp_level       4;
        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        include conf.d/elasticbeanstalk/*.conf;
    }
}

Old invalid documentation

Much documentation provided by Amazon is invalid since the behavior has changed for Amazon Linux 2. This config (and the rest of the repo from how it looks) for example only works for Amazon Linux 1: https://github.com/awsdocs/elastic-beanstalk-samples/blob/master/configuration-files/aws-provided/security-configuration/https-redirect/nodejs/https-redirect-nodejs.config

@Harsha-changejar
Copy link

Harsha-changejar commented Aug 31, 2021

Hello, Thnx for the above detailed explanation, what would be the configuration like if i had to turn off the server_tokens and what would be the location of such .conf file?

@Harsha-changejar
Copy link

How can we modify default server block?

@henhan
Copy link
Author

henhan commented Sep 17, 2021

How can we modify default server block?

As you can see in the full config, any file named "*.conf" and placed in the folder "conf.d" is autimatically included in the http block. So you can create a file called "server_tokens.conf" in that folder and just put the server_tokens instruction directly in that to get it included.

@maxkremer
Copy link

maxkremer commented Feb 14, 2022

Hi and thanks for the above. We have not been able to successfully enable gzip compression. Tried the gzip_proxied any; directive but still no luck. Any idea how to enable gzip compression for proxied content? It is off in the default conf server block above, what the best way to override this?

@esvignolo
Copy link

Hi! i have problems to setup gzip enabled too. Still trying to fix

@rlejeune
Copy link

Hi and thanks for the above. We have not been able to successfully enable gzip compression. Tried the gzip_proxied any; directive but still no luck. Any idea how to enable gzip compression for proxied content? It is off in the default conf server block above, what the best way to override this?

Hi @maxkremer, did you finally found a way to enable gzip by any chance? We have the same problem.

@henhan
Copy link
Author

henhan commented Mar 24, 2022

@rlejeune I would try overriding the whole default nginx config by placing a file in .platform/nginx/nginx.conf as described in the text. Switch gzip to on in that file and see if it works. If that doesn't do it, try adding the gzip_prozied statement there as well. Here's some more documentation on the various gzip directives: https://docs.nginx.com/nginx/admin-guide/web-server/compression/

@alejomoreira
Copy link

Hey, thanks for sharing this, do you know how can I use "Include php-fpm.php" inside a server match block in .platform/conf.d/server.conf, because when I change it directly from the instance it works fine, but when I deploy the app, it's like it's having problem with the paths of the file.

server {
    listen 80;
    listen [::]:80;
    server_name api.servername.com;
    root       /var/www/html/api/;
   
  ...other rules....
  
  # Rewrite urls without .php
    location / {
        rewrite ^/(.*)$ /$1.php last;
        Include default.d/php.conf;
    }
}

I'm gettint this error: open() "/var/proxy/staging/nginx/default.d/php.conf" failed (2: No such file or directory) in /var/proxy/staging/nginx/conf.d/servers.conf:58

it's like its using /var/proxy/staging instead /etc/nginx/
Thanks!

@henhan
Copy link
Author

henhan commented Sep 26, 2022

Hey, thanks for sharing this, do you know how can I use "Include php-fpm.php" inside a server match block in .platform/conf.d/server.conf, because when I change it directly from the instance it works fine, but when I deploy the app, it's like it's having problem with the paths of the file.

server {
    listen 80;
    listen [::]:80;
    server_name api.servername.com;
    root       /var/www/html/api/;
   
  ...other rules....
  
  # Rewrite urls without .php
    location / {
        rewrite ^/(.*)$ /$1.php last;
        Include default.d/php.conf;
    }
}

I'm gettint this error: open() "/var/proxy/staging/nginx/default.d/php.conf" failed (2: No such file or directory) in /var/proxy/staging/nginx/conf.d/servers.conf:58

it's like its using /var/proxy/staging instead /etc/nginx/ Thanks!

Have you put the conf file under .platform/nginx? I think that /var/proxy/staging is where the files are copied to for the deploy process to run. If your files are in the right place, it might be that it has to be a .conf file to be copied automatically. You might have to use a config hook to do what you need to get done. See the documentation about basic auth.

@voratham
Copy link

voratham commented May 3, 2023

i tried follow your step but not work

image

plartform: "Docker running on 64bit Amazon Linux 2/3.5.4"

@henhan
Copy link
Author

henhan commented May 9, 2023

i tried follow your step but not work

image

plartform: "Docker running on 64bit Amazon Linux 2/3.5.4"

It might be that the behavior for Docker is different. I have no experience of running Docker in elastic beanstalk.

@ankit-jds
Copy link

While Overriding the default location as mentioned in main gist
I am receiving this error in my eb-engine.log
nginx: [emerg] duplicate location "/" in /var/proxy/staging/nginx/nginx.conf:40

My EBS platform is Python 3.9 running on 64bit Amazon Linux 2023/4.0.0

How can i solve this??

@williams9438
Copy link

williams9438 commented May 26, 2023

i tried follow your step but not work

image

plartform: "Docker running on 64bit Amazon Linux 2/3.5.4"

it should work. the content of 00_application.conf should be the location of your static/public (htm/css etc or generated static asset) assets as the below example:

location /static/ {
alias /staticassets/;
expires 365d;
add_header Cache-Control "public";
}

Note: make sure to rename docker-compose.yml file if you have one in the root of your project for dev as beanstalk would pick it up and try to use it for deployment and result to error except you are specifically using that for your deployment.

@williams9438
Copy link

williams9438 commented May 26, 2023

nginx.conf

While Overriding the default location as mentioned in main gist I am receiving this error in my eb-engine.log nginx: [emerg] duplicate location "/" in /var/proxy/staging/nginx/nginx.conf:40

My EBS platform is Python 3.9 running on 64bit Amazon Linux 2023/4.0.0

How can i solve this??

From the look of this, it seems you have configured the nginx yourself from your dockerfile setup or something and it is interfrering with the EB nginx conf.
try to log into the EC2 instance and inspect the issue from there because the defult nginx dosen't use the location the error is coming from and also try to change block and not the entire nginx conf as error would always occur after plaform upgrade etc.
Elastic Beanstalk Nginx Configuration File nginx config for Elastic Beanstalk Amazon Linux 2 Default location (/etc/nginx/nginx.conf) not /var/proxy/staging/nginx/nginx.conf.

@lucas-mdiniz
Copy link

lucas-mdiniz commented Jun 19, 2023

i tried follow your step but not work

image

plartform: "Docker running on 64bit Amazon Linux 2/3.5.4"

@voratham

Anyone could you solve the issue with Docker platform? I'm using the same platform and I'm not able to setup the config.

@lucas-mdiniz
Copy link

For anyone using Docker platform.

Instead of uploading just the Dockerrun.aws.json with you should upload a zip file containing the Dockerrun.aws.json and the .platform directory.

@egarkavy
Copy link

@lucas-mdiniz thanks. This solution works
In my case I wanted to increase client_max_body_size so I created .platform\nginx\conf.d\elasticbeanstalk\01_client_max_body_size.conf with next contents: client_max_body_size 500M;
Then I do next:

  1. Generate json the same way but now have it's name just Dockerrun.aws.json, to satisfy default naming (before I was adding a version to this file)
  2. zip this json and .platform folder contents: zip -r <app_version>.app-name.zip Dockerrun.aws.json .platform/
  3. Push it to s3
  4. Upgrade EBT env the same way but now use .zip instead of Dockerrun.aws.json

@tfarkas86
Copy link

tfarkas86 commented Dec 8, 2023

nginx.conf

While Overriding the default location as mentioned in main gist I am receiving this error in my eb-engine.log nginx: [emerg] duplicate location "/" in /var/proxy/staging/nginx/nginx.conf:40
My EBS platform is Python 3.9 running on 64bit Amazon Linux 2023/4.0.0
How can i solve this??

From the look of this, it seems you have configured the nginx yourself from your dockerfile setup or something and it is interfrering with the EB nginx conf. try to log into the EC2 instance and inspect the issue from there because the defult nginx dosen't use the location the error is coming from and also try to change block and not the entire nginx conf as error would always occur after plaform upgrade etc. Elastic Beanstalk Nginx Configuration File nginx config for Elastic Beanstalk Amazon Linux 2 Default location (/etc/nginx/nginx.conf) not /var/proxy/staging/nginx/nginx.conf.

Are you sure about this? I'm not configuring any nginx properties other than the content in the .ebextensions folder, and I'm having exactly the same problem (duplicate "/" location). I "solved" it by overriding the nginx.conf file entirely, but I'd prefer a solution that is robust to any updates AWS might make to the default config. Could maybe try something inane like a commands key to modify the location block with sed or something ... personally I just need add a couple lines to it for basic authentication.

@ew-andriy
Copy link

nginx.conf

While Overriding the default location as mentioned in main gist I am receiving this error in my eb-engine.log nginx: [emerg] duplicate location "/" in /var/proxy/staging/nginx/nginx.conf:40
My EBS platform is Python 3.9 running on 64bit Amazon Linux 2023/4.0.0
How can i solve this??

From the look of this, it seems you have configured the nginx yourself from your dockerfile setup or something and it is interfrering with the EB nginx conf. try to log into the EC2 instance and inspect the issue from there because the defult nginx dosen't use the location the error is coming from and also try to change block and not the entire nginx conf as error would always occur after plaform upgrade etc. Elastic Beanstalk Nginx Configuration File nginx config for Elastic Beanstalk Amazon Linux 2 Default location (/etc/nginx/nginx.conf) not /var/proxy/staging/nginx/nginx.conf.

Are you sure about this? I'm not configuring any nginx properties other than the content in the .ebextensions folder, and I'm having exactly the same problem (duplicate "/" location). I "solved" it by overriding the nginx.conf file entirely, but I'd prefer a solution that is robust to any updates AWS might make to the default config. Could maybe try something inane like a commands key to modify the location block with sed or something ... personally I just need add a couple lines to it for basic authentication.

You solved problem? I have same

@vitalykarasik
Copy link

Are you sure about this? I'm not configuring any nginx properties other than the content in the .ebextensions folder, and I'm having exactly the same problem (duplicate "/" location). I "solved" it by overriding the nginx.conf file entirely, but I'd prefer a solution that is robust to any updates AWS might make to the default config. Could maybe try something inane like a commands key to modify the location block with sed or something ... personally I just need add a couple lines to it for basic authentication.

I have a similar question, regarding 'Document root' - I'd like to customize it without replacing the whole nginx.conf ().https://stackoverflow.com/questions/78232086/how-to-customize-nginx-document-root-in-aws-elastic-beanstalk-without-rewrite-wh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment