I have a small Flask application that I want to run on AWS Elastic Beanstalk.
The application deploys and runs fine but I've noticed that a custom HTTP Header (HTTP_CUSTOM_TOKEN) is not present in request.headers.
I'm assuming I'm missing something from the Apache configuration but am not very familiar with that environment.
What you need is something similar to what #Fartash suggested, just slightly different.
Add .ebextensions/python.config :
container_commands:
03wsgipass:
command: 'echo "WSGIPassAuthorization On" >> ../wsgi.conf'
as explained at Using the AWS Elastic Beanstalk Python Platform
Remove underscores from the header variables,
example:-
header_var_val = "some value"
replace it with -- headervarval = "some value"
You need to enable the WSGIPassAuthorization. If you do not specifically enable auth forwarding, apache will consume the required headers and your app won't receive it.
Add this to your *.config file in .ebextensions folder.
commands:
WSGIPassAuthorization:
command: sed -i.bak '/WSGIScriptAlias/ a WSGIPassAuthorization On' config.py
cwd: /opt/elasticbeanstalk/hooks
Related
I had this working before on AWS Linux AMI but no luck with AWS Linux 2.
I need to access my environment properties from the Nginx configuration file during the EB application deployment. It's a Single instance Node Server.
I did it like this with the AWS Linux AMI and it worked without a problem:
.ebextensions/00_options.config
option_settings:
aws:elasticbeanstalk:application:environment:
DOMAIN: socket.example.com
MASTER_DOMAIN: https://example.com
etc..
.ebextensions/10_proxy.config
... some configs ...
files:
/etc/nginx/conf.d/proxy.conf:
mode: "000644"
owner: root
group: root
content: |
upstream nodejs {
server 127.0.0.1:8081;
keepalive 256;
}
map $http_origin $cors_header {
hostnames;
default "";
`{"Fn::GetOptionSetting": {"Namespace": "aws:elasticbeanstalk:application:environment", "OptionName": "MASTER_DOMAIN"}}` "$http_origin";
}
server {
listen 80;
listen 8080;
server_name `{"Fn::GetOptionSetting": {"Namespace": "aws:elasticbeanstalk:application:environment", "OptionName": "DOMAIN"}}`;
location ~ /.well-known {
allow all;
root /usr/share/nginx/html;
}
location / {
return 301 https://$host$request_uri;
}
}
etc..
.... some more configs ....
I'm not including most of the configs above because they're not relevant.
So when I did this before, everything worked as expected. The config file inserted my properties and created the file in the /etc/nginx/conf.d/proxy.conf folder.
Now with AWS Linux 2 the specs have changed and we have to add our Nginx configuration files in the .platform/nginx/conf.d folder located in our application bundle root folder.
Here the reference ( see Reverse proxy configuration)
So I created a proxy.conf file in the location mentioned above with the content that was previously inserted in /etc/nginx/conf.d/proxy.conf.
.platform/nginx/conf.d/proxy.conf
upstream nodejs {
server 127.0.0.1:8081;
keepalive 256;
}
map $http_origin $cors_header {
hostnames;
default "";
`{"Fn::GetOptionSetting": {"Namespace": "aws:elasticbeanstalk:application:environment", "OptionName": "MASTER_DOMAIN"}}` "$http_origin";
}
etc...
And then the problems began..
This first trial throwed unexpected "{" in /var/proxy/staging/nginx/conf.d/proxy.conf:11 at me.
And after that I tried a lot of things. Tried it with ${MASTER_DOMAIN} and messed around with the new EB AWS Linux 2 hooks (see link above Platform hooks). All for no avail it seems like you can't access the properties from the Nginx configs. I've read an article or a documentation from Nginx mentioning something similar today but I can't find it anymore (did a lot of googling).
I also tried to create a config file like I did with the working version which purpose was to save a temp file somewhere with the included properties and then include this file in the needed .platform/nginx/conf.d/proxy.conf file because I started to think that there is no way to include them directly with the new specs.
.ebextensions/10_proxy.config
... some configs ....
files:
/var/proxy/staging/custom_folder/proxy.conf:
mode: "000644"
owner: root
group: root
content: |
etc...
.platform/nginx/conf.d/proxy.conf
include custom_folder/proxy.conf;
With this idea in mind I did a lot of nonsense, I created hooks for creating (mkdir) directories in which I tried to temporarily save the file which leaded to new permission errors. I wasn't able to give the proper permissions to prebuild, postdeploy files but this is another issue.
And a lot more of trying and failing...
But then I've read (also from the link above):
"If you configure your proxy to send traffic to multiple application processes, you can configure several environment properties, and use their values in both proxy configuration and your application code."
And hope came back.. Does this mean I actually CAN directly add environmental variables into the Nginx configs located in the .platform directory? ... I don't know.. Do you?
I could continue to describe all the things I tried all night long so I will stop here. I hope you get the issue. If not ask me and I will do my best to make all this understandable.
Also my mind isn't very clear anymore after 14 hours of battling this issue. I need a break.
If you did it to the end thank you for your time and help would be greatly appreciated.
Summary
One way to do it is to create a shell script in .platform/hooks/postdeploy.
Here is a simplified example, assuming you have an Elastic Beanstalk environment property called MASTER_DOMAIN:
#!/bin/bash
# write nginx config file
cat > /etc/nginx/conf.d/elasticbeanstalk/test.conf << LIMIT_STRING
location /test/ {
default_type text/html;
return 200 "nginx variable: \$host, and EB env property: $MASTER_DOMAIN";
}
LIMIT_STRING
# restart nginx service so the config takes effect
systemctl restart nginx.service
The location block from this example can be replaced by the nginx content from .ebextensions/10_proxy.config in the original post. No need for the Fn::GetOptionSetting stuff though.
I think you also need a duplicate script in .platform/confighooks/postdeploy.
Details below.
(sorry for the wall of text)
Environment variables in nginx
Actually, as discussed in here and here, it is not possible (out-of-the-box) to use os environment variables inside the http, server, or location blocks in nginx config files. There are some workarounds, such as using lua, perl, or templates, but let's not get into those. This part has nothing to do with AWS.
In the OP's original configuration for Amazon Linux AMI (AL1), using the files section in .ebextensions/10_proxy.config, they were actually using a shell script to write the nginx config file during deployment. The shell script expanded the environment variables, but the resulting proxy.conf for nginx did not actually access any environment variables.
That's why it worked on AL1.
Platform hooks
Now, for Amazon Linux 2 (AL2), we can do something similar using shell scripts in the .platform/hooks and .platform/confighooks folders.
These .platform hook scripts are executed as the root user, and they have access to the Elastic Beanstalk (EB) environment properties. The EB environment properties can be accessed just like normal OS environment variables, so there is no need to use the Fn::GetOptionSetting stuff.
Basically, we need to create a shell script that writes a file with the content from your original .ebextensions/10_proxy.config. However, there are two questions we need to consider:
Should we use a prebuild, predeploy, or postdeploy hook?
What is the proper destination directory for our nginx proxy.conf file?
File locations
To answer these questions, we have to refer to the AWS documentation for Extending Elastic Beanstalk Linux platforms, and specifically the Instance deployment workflow section.
... The current working directory (cwd) for platform hooks is the application's root directory. For prebuild and predeploy files it's the application staging directory, and for postdeploy files it's the current application directory. If one of the files fails (exits with a non-zero exit code), the deployment aborts and fails.
This is interesting, but leaves some questions, e.g. where is the "application staging directory" located? We can fill in the blanks by inspecting one of our deployment log files. Based on our eb-engine.log, here's what happens with the platform hooks and nginx config files during app deployment (skipping a lot of details):
the source bundle is downloaded from S3 and extracted to /var/app/staging/
platform hooks in .platform/hooks/prebuild/ are executed
proxy server configuration is copied from /var/app/staging/.platform/nginx/ to /var/proxy/staging/nginx
platform hooks in .platform/hooks/predeploy/ are executed
proxy server is started, configuration is copied from /var/proxy/staging/nginx/ to /etc/nginx
platform hooks in .platform/hooks/postdeploy/ are executed
Note, after deployment the app is located in /var/app/current.
Based on the above, there are several options:
Create a shell script in .platform/hooks/postdeploy that writes to /etc/nginx/conf.d/proxy.conf.
The nginx service is already running, at this stage, so we need to restart for the configuration to take effect.
Below is a minimal test example. In this example we write to the elasticbeanstalk subdirectory, because we just want to add a location inside the default server block. We can then visit the /test/ page in a browser, to check that the configuration works.
We use some bash io redirection (<<, >) to write the nginx config file.
Note that we need to escape any nginx variables, e.g. $host becomes \$host, otherwise the shell will interpret them as environment variables.
Also note that the shell scripts need to have execution permission, as explained under More about platform hooks in the docs.
#!/bin/bash
cat > /etc/nginx/conf.d/elasticbeanstalk/test.conf << LIMIT_STRING
location /test/ {
default_type text/html
return 200 "nginx variable: \$host, and EB env property: $MASTER_DOMAIN";
}
LIMIT_STRING
systemctl restart nginx.service
Alternatively, we could create a shell script in .platform/hooks/predeploy that writes to /var/proxy/staging/nginx/conf.d/proxy.conf.
There is no need to restart the nginx service in this case, because this hook is executed before the server configuration is applied.
BEWARE:
Not sure if this is a bug or a design feature, but our newly created proxy.conf disappears after a configuration deployment (as opposed to an application deployment), unless we put a duplicate script in the .platform/confighooks/postdeploy directory. Not very DRY...
EDIT: AWS support confirmed that we need duplicate scripts in hooks and confighooks in this case. The application example in the docs also shows some duplicates (at least duplicate filenames) in hooks and confighooks.
EDIT:
Instead of duplicating scripts, we can also write a confighook that calls a hook, e.g. .platform/confighooks/predeploy/01_my_confighook.sh could look like this:
#!/bin/bash
source "/var/app/current/.platform/hooks/predeploy/01_my_hook.sh"
Disclaimer: This was tested on a freshly created single instance EB environment with "Python 3.7 running on 64bit Amazon Linux 2/3.1.5" using all default configuration and the default AWS Python sample application (only extended with our custom hooks).
I'm trying to locate the staging directory as mentioned in the Elastic Beanstalk documentation.
The specified commands run as the root user, and are processed in alphabetical order by name. Container commands are run from the staging directory, where your source code is extracted prior to being deployed to the application server. Any changes you make to your source code in the staging directory with a container command will be included when the source is deployed to its final location.
For anyone else who ends up here, this worked for me:
/opt/elasticbeanstalk/bin/get-config platformconfig -k AppStagingDir
Amazon's documentation actually provides that exact command on this page (you have to expand the platformconfig – Constant configuration values section to see it).
The staging directory is in /var/app/ondeck. Or at least this is the case on their managed platform Puma with Ruby 2.5 running on 64bit Amazon Linux/2.11.0.
To check your own SSH into your Beanstalk instance and do:
/opt/elasticbeanstalk/lib/ruby/bin/get-config container -k app_staging_dir
You can also create a script in .ebextensions/ and issue a command that will be something like:
echo "We are here: $(pwd)"
You'll then be able to check eb-activity.log for that line.
While using command - eb deploy
I am getting below error. YAML is fine syntax wise
ERROR: InvalidParameterValueError - Each option setting in configuration file .ebextensions/environ-
v1.config in application version app-4c59-191023_045651 must be a map. Update each option setting in the configuration file.
.config file in .ebextensions folder which is in root of project
option_settings:
aws:elasticbeanstalk:application:environment:
PORT:8081
NODE_ENV:development
aws:autoscaling:launchconfiguration:
SecurityGroups:launch-123
I ran into the same issue running the AWS Deploy a Django App to Elastic Beanstalk (the tutorial does not seem to be up to date).
This AWS page has some info on the latest option setting formatting
It helped me resolve my issue which I think in your case would be including spaces after "PORT: ", "NODE_ENV: ", etc.
Also using an IDE that will highlight different words/parts of the file helped me understand how things were getting recognized.
have you tried double quotes in .config file like
"aws:elasticbeanstalk:application:environment":
instead of
aws:elasticbeanstalk:application:environment:
and, respectively,
"aws:autoscaling:launchconfiguration":
instead of
aws:autoscaling:launchconfiguration:
I have an environment in AWS with an ECS cluster, an EFS source and some services running on this cluster.
One of my services is the NginX web server which I use to serve our site and our services. As a solution to keep some sensitive and static configuration files we have chosen the EFS service. So, each service creates a volume from this EFS and mount it every time a container starts.
The problem is with NginX. I want to store my nginx.conf file into an EFS folder and after the NginX service starts, we want the container to copy this file at /etc/nginx/ folder in order for my NginX server to start with my configuration.
I've tried to build my own image including my configuration with success but this is not what we want.That means that we should build a new image every time we want to change a line on nginx.conf.
I've tried to create a script to run every time the container starts and copy my configuration but i didn't manage to make it play on ECS. Either the NginX failed to reload, either the syntax is wrong, either the file is not available.
#!/bin/bash
cp /efs/nginx.conf /etc/nginx/
nginx -s reload
Ι considered to find out how to create a cron job to run every X minutes and copy my nginx.conf to etc/nginx but this seems to be a stupid approach.
I made like 60 different task definitions revisions in order to find out how this CMD Environment option works on ECS. Of course the most of them has to do with the syntax and i get bach errors like "invalid option: bash" or "invalid option: /tmp/1.sh" etc
Samples:
1.Command ["cp","/efs/nginx.conf /etc/nginx/"]
2.Entry point ["nginx","-g","daemon off;"]
Command ["cp /efs/nginx.conf /etc/nginx/"]
Entry point: ["nginx","-g","daemon off"]
Command: ["/bin/sh","cp","/efs/nginx.conf/","/etc/nginx/"]
Command ["[\"cp\"","\"/efs/nginx.conf\"","\"/etc/nginx/\"]","[\"nginx\"","\"-g\"","\"daemon off;\"]"]
Command ["cp /efs/nginx.conf /etc/nginx/","nginx -g daemon off;"]
Command ["cp","/efs/nginx.conf /etc/nginx/","nginx -g daemon off;"]
-
Does anyone knows or does anyone already implement this solution on ECS?
To replace /etc/nginx/nginx.conf with a modified one from a binded volume?
Thanks in advance
SOLUTION:
As I mention at my question above, I'd like to use a static nginx.conf file, which will be into an EFS folder, into my nginx service container.
My task definition is simple like this
FROM nginx
EXPOSE 80
RUN mkdir /etc/nginx/html
Through ECS task definition I create a volume and then a mounting point which is an easy process and works fine. The problem was in the entrypoint field which supposed to include my script's directory and to my script itself.
At ECS task definition Environment entrypoint field i putted
sh,-c,/efs/docker-cmd-nginx.sh
and my script is just the following
#!/bin/dash
cp /efs/nginx.conf /etc/nginx/ &&
nginx -g "daemon off;"
PS: The problem probably was at:
my script which I didn't use double quotes at the daemon off; part but I was using double quotes on the whole line nginx -g daemon off;
my script was trying to reload nginx which was not even running yet.
my attempt to put the commands seperately at my task's entrypoint was wrong, syntax-wise for sure and maybe strategy-wise as well.
So I have the below kue.config file that works (ie runs fine) on my EC2 instance, not work when I try to use it as an .ebextension on Elastic Beanstalk?
description "start kue server"
start on filesystem and started networking
stop on shutdown
script
touch /var/log/forever.log
touch /var/log/stat_out.log
touch /var/log/stat_err.log
rm /var/log/forever.log
rm /var/log/stat_out.log
rm /var/log/stat_err.log
NODE_ENV=production forever start --spinSleepTime 10000 -l /var/log/forever.log -o /var/log/stat_out.log -e /var/log/stat_err.log /home/ec2-user/mykue/server.js
/bin/echo 'Server should be started we ran etc/init/kue.config' >> ../home/ec2-user/wearego
end script
I get the following ERROR:
Top level element in configuration file burrokue/.ebextensions/kue.config in application version burrokue3 must be a map. Update the top level element in the configuration file.
You are confusing the .config files up.
The kue.config file you're using is a config file for configuring the Kue service: https://github.com/Automattic/kue
However, the .config files in an .ebextensions folder is not the same. They are for a different purpose: to configure the Elastic Beanstalk service.
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ebextensions.html
The file formats are different.
While they both have names ending in .config, the are not the same thing.
In your case, assuming that you already have Kue installed on your Elastic Beanstalk EC2 instances, you can create a .ebextensions file that will instruct Elastic Beanstalk to create your kue.config file.