-
Notifications
You must be signed in to change notification settings - Fork 4
/
nginx-explorer.conf
161 lines (148 loc) · 6.12 KB
/
nginx-explorer.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# Credits:
# - https://github.com/h5bp/server-configs-nginx/tree/main
# - https://gist.github.com/eatnumber1/92e94086dafc7194077df4a6b45b2b75
# - https://serverfault.com/questions/421046/how-to-limit-nginx-auth-basic-re-tries/1060487#1060487
# | Config path | default |
# |--------------------|--------------------------|
# | listing / download | /home/user/downloads |
# | uploads | /home/user/uploads/ |
# | app / css / js | /var/www/ngxp/ |
# | user access uri | /opt/ngxp/accessuri.map |
# | user basic auth | /opt/ngxp/basic.htpasswd |
map "" $ngxp_html_header {
default "<!DOCTYPE html><html><link rel='shortcut icon' href='data:;base64,=' /><link rel='stylesheet' href='/___ngxp/main.css' /><script name='NgxEx' favicon='🗃️' status='$status' date-format='' user='$username' access='$user_cookie_access' login='/___ngxp/login' logout='/___ngxp/logout' upload='/___ngxp/upload/' upload-max-size='209715200' icons='/___ngxp/icons/' src='/___ngxp/main.js'></script>";
}
map $uri $cond_filter { # sub_filter "<html>" $cond_filter;
~/$ $ngxp_html_header; # directory listing
default "<html>"; # file
}
geo $local_peer { # local network addresses
default "wan_anon";
fe80::/10 "lan_anon";
::1/128 "lan_anon";
127.0.0.1/32 "lan_anon";
192.168.0.0/16 "lan_anon";
10.0.0.0/8 "lan_anon";
}
map $cookie_ngxp $username {
~^lan_anon:.* ""; # dont trust user input
~^wan_anon:.* "";
~^(?<var>[^:]+):.* $var; # get user from client sent cookie
default $local_peer; # use ip name when empty
}
map $username $user_cookie { # map basic auth users to access and a secret
default "";
include /opt/ngxp/accessuri.map;
}
map $user_cookie $user_cookie_access {
~^([^:]+):([^:]+):(?<var>[^:]+)$ $var; # user access from user cookie
default "";
}
map ${user_cookie_access}?${uri} $uri_access { # request uri access
~^([^\?]+)\?\1.*$ 1; # if $uri startwith $user_cookie_access
default 0;
}
map ${cookie_ngxp}?${user_cookie} $user_cookie_equal {
~^([^\?]+)\?\1$ 1; # if $user_cookie == $cookie_ngxp
default 0;
}
map ${user_cookie_equal}${uri_access}_${username} $user_authorized {
~^11_.*$ 1; # everything good authorize
01_lan_anon 1; # special case for lan_anon (don't need cookie)
01_wan_anon 1; # special case for wan_anon (don't need cookie)
default 0;
}
# rate limit for login
limit_req_status 429;
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/m;
# gzip
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types text/javascript text/js text/css text/xml text/plain application/javascript application/xml application/x-javascript image/svg+xml;
# pref file send
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
sendfile on;
sendfile_max_chunk 2m;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Headers CORS
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Expose-Headers 'Content-Length';
add_header Access-Control-Expose-Headers 'Content-Disposition';
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
charset UTF-8;
charset_types text/css text/plain text/vnd.wap.wml text/javascript text/markdown application/json application/manifest+json;
server_tokens off;
server {
listen 8080;
listen [::]:8080;
location @401 { types { } default_type "text/html; charset=utf-8"; return 401 $ngxp_html_header; }
location @403 { types { } default_type "text/html; charset=utf-8"; return 403 $ngxp_html_header; }
location @404 { types { } default_type "text/html; charset=utf-8"; return 404 $ngxp_html_header; }
error_page 401 = @401;
error_page 403 = @403;
error_page 404 = @404;
location ^~ /___ngxp/ {
# this is where app files (main.js, icons) are,
# drawback is that a folder named '___ngxp' cannot be indexed
alias /var/www/ngxp/;
}
location @login_success {
set $username $remote_user;
add_header Set-Cookie "ngxp=$user_cookie; max-age=15552000; path=/; SameSite=Lax; Secure; HttpOnly";
return 200 "login success";
}
location ^~ /___ngxp/login { # login
limit_except POST { deny all; }
auth_basic "Login";
auth_delay 1s;
auth_basic_user_file /opt/ngxp/basic.htpasswd;
limit_req zone=auth burst=20 nodelay;
try_files _ @login_success;
}
location ^~ /___ngxp/logout { # logout
limit_except POST { deny all; }
add_header Set-Cookie "ngxp=; Max-Age=0; path=/; SameSite=Lax; Secure; HttpOnly";
return 201; # cookie removed
}
location / {
root /home/user/downloads; # file listing and download
if ($user_authorized = 0) { return 401; }
# Random id so nginx do not redirect / to index.html
# remove if you want directories with index.html to be rendered
index 953b12d3-5ab2-49ad-8f49-6ea27f3a9994;
autoindex on; # File listing (index) in html format
autoindex_format html;
autoindex_exact_size on;
sub_filter_once on;
sub_filter_last_modified on;
sub_filter "<html>" $cond_filter;
}
location ^~ /___ngxp/upload/ { # upload endpoint, remove to disable upload
limit_except GET POST { deny all; }
if ($user_authorized = 0) { return 401; }
client_body_temp_path /home/user/uploads/; # upload path
client_body_in_file_only on; # store on disk
client_body_buffer_size 16m;
client_max_body_size 256m;
client_body_timeout 2h;
proxy_set_body off; # do not send file to proxy
proxy_pass http://[::1]:4000/$request_method;
}
}
# Upload dummy server that return 200 to finish files upload
# Remove to disable upload
server {
listen [::1]:4000;
location /POST { return 204; }
location /GET { return 200; }
}