SignatureDoesNotMatch Error while downloading file using X-Accel-Redirect - ruby-on-rails-3

There are several questions related to this but this use case is slightlt different.
In Rails - In my controller I set response header explicitly :
response.headers['X-Accel-Redirect'] = "some_url"
Nginx Config
location ~* ^/some_url/(.*){
set $s3_bucket '$arg_bucket_name';
set $aws_access_key 'AWSAccessKeyId=$arg_AWSAccessKeyId';
set $url_expires 'Expires=$arg_Expires';
set $url_signature 'Signature=$arg_Signature';
set $url_full '$1?$aws_access_key&$url_expires&$url_signature';
proxy_hide_header Content-Disposition;
add_header Content-Disposition 'attachment; filename=$arg_filename';
proxy_hide_header x-amz-id-2;
proxy_hide_header x-amz-request-id;
proxy_buffering off;
proxy_intercept_errors on;
resolver 4.2.2.2 8.8.8.8 valid=300s;
proxy_pass https://$s3_bucket/$url_full;
}
Using this to download 100 of files through nginx ,in few cases I am getting error
SignatureDoesNotMatch
The request signature we calculated does not match with the signature you provide.

Related

How to avoid timeout (net::ERR_HTTP2_PING_FAILED 8mins) when uploading files with axios post method?

I'm doing some big file (10GB+) uploading so what I did is slicing the file to some 3MB chunks and then upload them. It works fine until I got a really bad network scenario (cannot finished uploading a chunk with 8mins). The browser(chrome) gave me an net::ERR_HTTP2_PING_FAILED error and after checking on the Internet it basically means timeout. I changed timeout setting for this api in Nginx to 99999, it will not give me 504 error (meaning nginx didn't cut the connection because of timeout) but the maximum time for me to upload a slice is 8mins. I think this problem is caused by browser itself so I checked the browser concole. The thing is the network page shows that "uploadSlice " used 8mins to initial connection! But the progress bar still going so I have no idea how to solve this.
Here is that error screenshot:
enter image description here
Here is my code for the upload slice part. (I use axios and a post method to send chunk)
request(formData,cancel) {
let uid = formData.get("uid");
let lastLoad = 0;
//formData contains file's chunk and other info
return this.$http.post("/file/uploadSlice", formData, {
headers: { "Content-Type": "multipart/form-data" },
//this part is using for progress bar calculation
onUploadProgress: (progressEvent) => {
let loadThisTime = progressEvent.loaded - lastLoad;
lastLoad = progressEvent.loaded;
this.$store.dispatch("updateState/addCompleteNessAsync",[uid,loadThisTime]);
},
cancelToken: cancel
});
},
And here is my setting for this api in Nginx:
(in default.conf)
location /api/file/uploadSlice {
proxy_pass http://172.17.0.1:9090/file/uploadSlice/;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_read_timeout 99999;
proxy_connect_timeout 99999;
proxy_send_timeout 99999;
}
in nginx.conf:
...
http{
...
keepalive_timeout 65;
client_max_body_size 50m;
client_body_buffer_size 5m;
client_header_timeout 120s;
...
include /etc/nginx/conf.d/*.conf;
}

NGINX make directory readonly unless authentication provided

I have a directory public, where I will upload various files. I want those files to be downloadable without any authentication.
However, I also want to be able to edit and add new files using WebDAV, if authentication is provided. Is there any way I can have both behaviors on the same directory (location)?
I tried the following hack:
location /public/ {
if ($remote_user != "") {
return 302 e;
}
auth_basic off;
fancyindex off;
dav_methods off;
}
location /public/e {
}
However, I could not find a way to make /public/e index /public/ instead.
I also tried the following:
location /public/ {
if ($remote_user = "") {
auth_basic off;
fancyindex off;
dav_methods off;
}
}
But Nginx complained that I cannot have those directives in an if-statement.
I also tried:
location /public/ {
set $authenticated off;
if ($remote_user != "") {
set $authenticated on;
}
auth_basic $authenticated;
fancyindex $authenticated;
dav_methods $authenticated;
}
But Nginx said a variable is invalid, on or off was expected.
I also thought about making two directories, public and public-webdav, which are symlinked to the same directory, and assign different nginx locations to them, but I was hoping for a cleaner solution.
Thanks!
I solved it using this method:
location #public {
auth_basic off;
}
location /public/ {
if ($remote_user = "") {
error_page 418 = #public;
return 418;
}
}
That is, creating a custom handler for error 418 (teapot) and forcing that error.

Nginx: Is it possible to get response retuned from auth_request

I am using auth module for nginx. (http://nginx.org/en/docs/http/ngx_http_auth_request_module.html)
Is it possible somehow to store the response from the /auth, so I can send it as a request body to another endpoint.
location /private/ {
auth_request /auth;
proxy_pass ...
proxy_set_body 'Here I want to put /auth response. How?';
}
location = /auth {
proxy_pass ...
}
Short answer:
No, you can't.
Long answer:
You can't get body of a response returned to auth_request. You can get a header returned in the response though, using the auth_request_set directive:
location / {
auth_request /auth;
auth_request_set $auth_foo $upstream_http_foo;
proxy_pass ...
proxy_set_body $auth_foo;
}
The above configuration will set the $auth_foo variable to the value of Foo header of an auth subrequest.

How to edit 'Index of etc' pages on Nginx and - Make them responsive?

I am using Ubuntu Natty 12 and I am using NGINX. (It would insane to consider bloated Apache these days)
What I want to do is edit the default index page templates and add some Meta ViewPorts and styling to them. I know Apache has IndexHeadInsert:
# META VIEWPORT
IndexHeadInsert "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
Examples would be then:
http://nginx.org/download/
http://bluu.co.uk/fonts/
https://archive.apache.org/dist/ant/binaries/
Does anyone know where to start on NGINX?
Nginx has sub module for replace part of answer.
http://nginx.org/en/docs/http/ngx_http_sub_module.html
It's work well with all answers including autoindex. Just check if your nginx has this module (type nginx -V), may be you need nginx-full package.
location / {
autoindex on;
sub_filter_once on;
sub_filter <head><title> "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>";
}
If you need this replace only for one location (/download/, for example), just put it in location block.
location = /download/ {
autoindex on;
sub_filter_once on;
sub_filter <head><title> "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>";
}
= here match /download/ only, but do not match /download/file...
If you have lot of locations and want to keep rules in one place, you can try to redirect 403 error to named location
location #subfilter {
autoindex on;
sub_filter <head><title> "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>";
}
location = /files/ {
error_page 403 =200 #subfilter;
}
location = /download/ {
error_page 403 =200 #subfilter;
}
But sub module still wery weak because you can use only one sub_filter directive =( It's possible to hack with proxy request to self, but it's bad solution. Better to use 3rd party module https://github.com/yaoweibin/ngx_http_substitutions_filter_module
html5, all the same:
sub_filter "<html>\r\n<head><title>" "<!DOCTYPE html>\r\n<html>\r\n<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>";

Nginx config: how to use auth_basic authentication if ssl_client_certificate none provided?

I'm trying to set up Nginx server as follows:
First, the server should check whether the user provides the client SSL certificate (via ssl_client_certificate).
If the SSL certificate is provided, then give access to the site,
If the SSL certificate is NOT provided, then ask the user to enter a password and logs through auth_basic.
I was able to configure both the authentication method at the same time. But this config is superfluous.
To make check, whether the user provides its SSL certificate I try the config like this:
18: if ($ssl_client_verify != SUCCESS) {
19: auth_basic "Please login";
20: auth_basic_user_file .passfile;
21: }
But Nginx returns an error:
"auth_basic" directive is not allowed here in .../ssl.conf:19
How can I to set the condition in this case?
You can set auth_basic configuration in the if clause like this:
server {
listen 443;
auth_basic_user_file .htpasswd;
ssl_client_certificate ca.cert;
ssl_verify_client optional;
...
location / {
...
if ($ssl_client_verify = SUCCESS) {
set $auth_basic off;
}
if ($ssl_client_verify != SUCCESS) {
set $auth_basic Restricted;
}
auth_basic $auth_basic;
}
}
Now, authentication falls back to HTTP Basic if no client certificate has been provided (or if validation failed).
I'm unable to test this currently, but would something like this work?
server {
listen 80;
server_name www.example.com example.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443;
...
if ($ssl_client_verify != SUCCESS) {
rewrite ^ http://auth.example.com/ permanent;
}
location / {
...
}
}
server {
listen 80;
server_name auth.example.com;
location / {
auth_basic "Please login";
auth_basic_user_file .passfile;
}
}
So basically:
- Accept all initial request (on port 80 for whatever name you're using) and rewrite to ssl
- Check if there's an the client is verified.
- If not, rewrite to an alternate domain that uses basic auth
Like I said, I can't test it right now, but I'll try to get around to it! Let me know if it helps, I'm interested to see if it works.
You may try using a map.
map $ssl_client_verify $var_auth_basic {
default off;
SUCCESS "Please login";
}
server {
....
auth_basic $var_auth_basic;
auth_basic_user_file .passfile;
that way the value depends on $ssl_client_verify but is alsa always defined and auth_basic and auth_basic_user_file is always inside server { block.
Nginx provides no way to fall back to basic authentication when client cert fails. As an alternative you can use variables to restrict access:
location / {
if ($ssl_client_verify = "SUCCESS") {
set $authorized 1;
}
if ($authorized != 1) {
error_page 401 #basicauth;
return 401;
}
}
location #basicauth {
auth_basic "Please login";
auth_basic_user_file .passfile;
set $authorized 1;
rewrite /(.*) /$1;
}
*keep in mind that IfIsEvil and these rules may work incorrectly or interfere with other parts of a larger configuration.
Forget about it, it won't work.
The reason why it fails is because if is not part of the general configuration module as one should believe. if is part of the rewrite module and auth_basic is another module. You just cannot have dynamic vhosts with basic auth.
On the other hand...
You can have dynamic vhosts with their own error pages. The following example is designed for a custom 404 page but you can implement it into your code.
server {
listen 80;
server_name _;
set $site_root /data/www/$host;
location / {
root $site_root;
}
error_page 404 =404 /404.html;
location /404.html {
root $site_root/error_files;
internal;
error_page 404 =404 #fallback_404;
}
location #fallback_404 {
root /var/www/;
try_files /404.html =404;
internal;
}
error_log /var/log/nginx/error.log info;
access_log /var/log/nginx/access.log;
}
What happens...
you are telling Nginx to use /404.html in case of HTTP_NOT_FOUND.
changing the location root to match the Web site error_pages directory.
internal redirection
returning a 404 http code
configure the fallback 404 page in location #fallback_404: In this location, the root is changed to /var/www/ so it will read files from that path instead of $site_root
at the last stage the code returns /var/www/404.html if it exists with a 404 http code.
NOTE: According to Nginx documentation :
Specifies that a given location can only be used for internal
requests. For external requests, the client error 404 (Not Found) is
returned. Internal requests are the following:
requests redirected by the error_page, index, random_index, and try_files directives;
requests redirected by the “X-Accel-Redirect” response header field from an upstream server;
subrequests formed by the “include virtual” command of the ngx_http_ssi_module module and by the ngx_http_addition_module module
directives;
requests changed by the rewrite directive.
Also:
There is a limit of 10 internal redirects per request to prevent
request processing cycles that can occur in incorrect configurations.
If this limit is reached, the error 500 (Internal Server Error) is
returned. In such cases, the “rewrite or internal redirection cycle”
message can be seen in the error log.
Check this link for more, hope that helps.