caching & ssl in nginx - caching

Trying to get nginx to cache static assets, but getting a 404 on everything. If I take out the cache block it works fine, but obviously it's not caching. How can I set this up so that things will get cached by nginx?
server {
listen 80;
return 301 https://$host$request_uri;
}
upstream backends {
server 127.0.0.1:8443;
#server 192.168.100.101:80;
}
server {
listen 443 ssl; # 'ssl' parameter tells NGINX to decrypt the traffic
server_name example.com;
ssl_certificate /etc/nginx/ssl/nginx.crt; # The certificate file
ssl_certificate_key /etc/nginx/ssl/nginx.key; # The private key file
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
location / {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://backends;
}
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 168h;
}
}

nginx chooses one location block to process a request. You need to replicate or inherit common functionality. For example:
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://backends;
}
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 168h;
proxy_pass http://backends;
}
Replicating complex configurations is best done with a separate file by using the include directive.

Related

How to alter existing nginx config into a reverse proxy for multiple local machines with working lets-encrypt certificate

Let me preface this by saying most of my "experience" comes from blindly copypasting config lines from various blogs and sites like this and hoping for the best.
Currently I have a setup like this:
Dynamic ddns hostname pointed at my public IP redirecting incoming traffic from ports 80 and 443 to a LXC container with nextcloud + certificate from letsencrypt for the same ddns hostname. So far so good.
this is the relevant nginx config:
server {
server_name stats;
listen 9753 default_server;
listen [::]:9753 default_server;
location /nginx-status {
stub_status on;
access_log off;
allow 127.0.0.1;
allow ::1;
deny all;
}
location ^~ /.well-known/acme-challenge {
proxy_pass http://127.0.0.1:81;
proxy_set_header Host $host;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name nextcloud;
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
client_max_body_size 10240M;
root /var/www/nextcloud/;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location = /.well-known/carddav {
return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
return 301 $scheme://$host/remote.php/dav;
}
location / {
rewrite ^ /index.php;
}
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
deny all;
}
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}
location ^~ /apps/rainloop/app/data {
deny all;
}
location ~ \.(?:flv|mp4|mov|m4a)$ {
mp4;
mp4_buffer_size 100M;
mp4_max_buffer_size 1024M;
fastcgi_split_path_info ^(.+?.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
include php_optimization.conf;
}
location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+).php(?:$|\/) {
fastcgi_split_path_info ^(.+?.php)(\/.*|)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
include php_optimization.conf;
}
location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
try_files $uri/ =404;
index index.php;
}
location ~ .(?:css|js|woff2?|svg|gif|map|png|html|ttf|ico|jpg|jpeg)$ {
try_files $uri /index.php$request_uri;
access_log off;
expires 30d;
}
}
My original vision for altering this was to use nextcloud.ddns.net to access my nextcloud as before, but also be able to reverse proxy to different local machines via nextcloud.ddns.net/whatever, nextcloud.ddns.net/something etc. Why? Because in my absolute failure of understanding the underlying technology I envisioned this would keep using the already valid ssl certificate for nextcloud.ddns.net without me having to obtain a new certificate for each destination. Does it work like this? I still do not know, but that didn't stop me from trying. I tried including a new location /whatever directive in various places, but all I achieved was a) it not working at all, b) redirecting me to the original nextcloud, c) only working while connected to local lan.
Seeing as I wasn't getting anywhere I went the other way and registered another ddns hostname, pointed that at the same public IP and included this block at the top of the nginx.conf:
server {
listen 443 ssl;
server_name other_hostname.ddns.net;
location / {
proxy_pass http://different_local_machine.lan/;
}
}
This works but obviously complains about the certificate being issued to nextcloud.ddns.net not to other_hostname.ddns.net
Onto my questions then:
Is it at all possible to set it up as I originally thought of with using 1 ddns hostname with different /suffixes or is this not how it works at all?
How would I go about getting multiple lets-encrypt certificates in the working scenario with multiple ddns hostnames? I'm worried if I follow the same instructions as I did to get the cert for the nextcloud I'll end up messing that, as that is still the only internet-facing nginx.
How "safe" would I be in just ignoring the warning? I mean I know the certificate is for different hostname, but I actually know it's still a valid certificate.
Again I apologise for my technical shortcomings, it took me few days to find out that what I want to achieve is called reverse proxy and it didn't improve much from there, but I think what I want to achieve should be possible with help from internet strangers without me having to complete a semester of Computer Science
Thanks for any help!
Here is an example that can be used to handle this ... you may need to tweak the setup for your own needs ...
I use this in an nginx docker that is networked to two containers
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
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"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
In the /etc/nginx/conf.d/ directory resides the configuration files for each container ..
-- in site1.conf --
upstream production{
server container_name1:80;
}
server {
server_name site1.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Access-Control-Allow-Origin *;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://production/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/site1.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/site1.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = site1.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name site1.com;
listen 80;
return 404; # managed by Certbot
}
-- in site2.conf --
upstream production_admin{
server container_name2:80;
}
server {
server_name admin.site1.com;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
add_header Access-Control-Allow-Origin *;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://production_admin/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/site1.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/site1.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = admin.site1.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name admin.site1.com;
listen 80;
return 404; # managed by Certbot
}
Upstream will set the name that is used in the proxypass and just serve off port 80 for server. This should get you started
For what it's worth if anybody is as hopeless as I am and has this exact same problem, I managed to discover solution on another forum. 1 freaking line, that was it. proxy_set_header Referer $http_referer; What does it do? How should I know? It makes my stuff work as I want though and that's all I care about.
So the full working location block looks like:
location ~ /something {
proxy_pass http://somehost.lan:someport;
proxy_set_header Referer $http_referer;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
discussion that led me to the "discovery" : https://unix.stackexchange.com/questions/290141/nginx-reverse-proxy-redirection Bottom post, 1st comment.

How to point http to https subdomain in NGINX?

I am working on a Spring Boot app that servers content for 3 types of users. All three users "live" in the same application. I want to configure NGINX to 1) redirect all http to https and 2) redirect traffic as follows:
http to https://www.example.com
http://b2b.example.com to https://b2b.example.com/b2b (Ideally not showing the "/b2b". Here all the b2b spring boot endpoints are listening)
So far this is my NGINX conf:
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
server {
listen 443;
server_name example.com www.example.com;
ssl on;
ssl_certificate ...;
ssl_certificate_key ...;
ssl_session_cache shared:SSL:10m;
access_log ...;
error_log ...;
location / {
proxy_pass http://localhost:5050;
proxy_set_header Host $host;
# re-write redirects to http as to https, example: /home
proxy_redirect http:// https://;
}
}
server {
listen 443;
server_name b2b.example.com;
ssl on;
ssl_certificate ...;
ssl_certificate_key ...;
ssl_session_cache shared:SSL:10m;
access_log ...;
error_log ...;
location / {
proxy_pass http://localhost:5050/b2b;
proxy_set_header Host $host;
# re-write redirects to http as to https, example: /home
proxy_redirect http:// https://;
}
}
On Sring Boot side, all B2B endpoints are listening to a pattern starting with "B2B". So for example the login page for these users is .../B2B/login. Right now if I go to b2b.example.com I get redirected to b2b.example.com/B2B/login. What I want is the browser to show "B2B.example.com/login" and to display the "/B2B/login" page. All the B2B sites omitting the "/B2B" part in the URL.

"Naked domain" unexpectedly closed the connection on my computer

I am experiencing ERR_CONNECTION_CLOSED on all web browsers for the naked domain of my website in my computer. I don't find this issue in any other device other than my computer. The www version loads fine as well.
I have tried clear browser history for last 24 hours, deleted the cache and cookies. It didn't make any difference.
This is my nginx configuration.
upstream app_server {
server unix:/run/gunicorn.sock fail_timeout=0;
}
server {
server_name mydomain.com www.mydomain.com;
location = /favicon.ico { access_log off; log_not_found off; }
location /assets/ {
root /home/djangoadmin/v/myappname;
}
location /media/ {
root /home/djangoadmin/myapp/myappname;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; # <-
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://app_server;
break;
}
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = mydomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name mydomain.com www.mydomain.com;
return 404; # managed by Certbot
}
Is this a device issue or something related to my nginx configuration? How to fix this?
Finally figured it out! The reason was my computer's /etc/hosts had a entry for the naked domain pointing to 127.0.0.1. Removing it fixed the issue.

Nginx fails to load static files after I declared them using location

I've configured Nginx as you can see:
server {
listen 443 ssl;
ssl on;
ssl_certificate /etc/nginx/ssl/bundle.crt;
ssl_certificate_key /etc/nginx/ssl/privateKey.key;
location /webmin/ {
proxy_pass http://127.0.0.1:10000;
}
server {
listen 80;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/bundle.crt;
ssl_certificate_key /etc/nginx/ssl/privateKey.key;
server_name localjob.it;
access_log off;
location / {
alias /webapps/sitoweb/;
}
Now if I go on mysite.com the page is loaded with the CSS, but if I add:
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 168h;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
Now if I go on mysite.com the page can't load CSS.
I can't understand the reason!!
Nginx locations exclusive so your alias inslide root location doesn't applies to another locations. Also it's a bit misuse, just use root directive in server block.
server {
listen 80;
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/bundle.crt;
ssl_certificate_key /etc/nginx/ssl/privateKey.key;
server_name localjob.it;
access_log off;
root /webapps/sitoweb;
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 168h;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
}

Serving two sites from one server with Nginx

I have a Rails app up and running on my server and now I'd like to add another one.
I want Nginx to check what the request is for and split traffic based on domain name
Both sites have their own nginx.conf symlinked into sites-enabled, but I get an error starting nginx Starting nginx: nginx: [emerg] duplicate listen options for 0.0.0.0:80 in /etc/nginx/sites-enabled/bubbles:6
They are both listening on 80 but for different things.
Site #1
upstream blog_unicorn {
server unix:/tmp/unicorn.blog.sock fail_timeout=0;
}
server {
listen 80 default deferred;
server_name walrus.com www.walrus.com;
root /home/deployer/apps/blog/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #blog_unicorn;
location #blog_unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://blog_unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
Site two:
upstream bubbles_unicorn {
server unix:/tmp/unicorn.bubbles.sock fail_timeout=0;
}
server {
listen 80 default deferred;
server_name bubbles.com www.bubbles.com;
root /home/deployer/apps/bubbles/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #bubbles_unicorn;
location #bubbles_unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://bubbles_unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
The documentation says:
The default_server parameter, if present, will cause the server to become the default server for the specified address:port pair.
It's also obvious, there can be only one default server.
And it is also says:
A listen directive can have several additional parameters specific to socket-related system calls. They can be specified in any listen directive, but only once for the given address:port pair.
So, you should remove default and deferred from one of the listen 80 directives. And same applies to ipv6only=on directive as well.
Just hit this same issue, but the duplicate default_server directive was not the only cause of this message.
You can only use the backlog parameter on one of the server_name directives.
Example
site 1:
server {
listen 80 default_server backlog=2048;
server_name www.example.com;
location / {
proxy_pass http://www_server;
}
site 2:
server {
listen 80; ## NOT NOT DUPLICATE THESE SETTINGS 'default_server backlog=2048;'
server_name blogs.example.com;
location / {
proxy_pass http://blog_server;
}
I was having the same issue. I fixed it by modifying my /etc/nginx/sites-available/example2.com file. I changed the server block to
server {
listen 443 ssl; # modified: was listen 80;
listen [::]:443; #modified: was listen [::]:80;
. . .
}
And in /etc/nginx/sites-available/example1.com I commented out listen 80 and listen [::]:80 because the server block had already been configured for 443.

Resources