Cached version of the endpoint in nginx - nginx

I would like to have alternative urls for my API endpoints that would use nginx caching. For example a url /cached/api/songs/latest should return a cached version of the endpoint /api/songs/latest coming from the PHP engine.
I came up with this configuration but it does not work. Could you please advise what am I doing wrong?
proxy_cache_path /data/cache/nginx keys_zone=one:10m loader_threshold=300
loader_files=200 max_size=200m;
server {
server_name api.myserver.com;
# SSL configuration
listen 443 ssl;
ssl_certificate ...
ssl_certificate_key ...
root /data/myapp/public;
index index.html index.php;
# cached version of the endpoints
location ~ ^/cached/.*$ {
rewrite ^/cached(.*)$ /$1 break;
proxy_pass https://127.0.0.1:443;
proxy_cache_valid any 60m;
}
# standard includes
include global/restrictions.conf;
include global/common_php.conf;
include global/static_assets.conf;
}

Related

How to redirect API calls with nginx?

Using nginx I am trying to redirect API calls to an external API provider website but after a lot of research and tries I feel I miss something important.
For example, my goal is when I open https://mywebsite/api/somedata, then a remote API provider is called https://api-somewebsite.com/somedata.
My basic try was:
location /api/ {
proxy_pass https://api-somewebsite.com/;
}
I added a log format to try to get more informations:
log_format upstreamlog '[$time_local] $remote_addr - $remote_user - $server_name $host to: $upstream_addr: $request $status upstream_response_time $upstream_response_time msec $msec request_time $request_time';
Then used it to log the calls:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
}
And it seems that the /api/ part is not well removed:
[21/Sep/2022:11:23:17 -0400] 88.163.105.196 - - - mywebsite.com mywebsite.com to: xxx.xx.xx.xx:xxx, xxx.xx.xx.xx:xxx: GET /api/somedata HTTP/1.1 502 upstream_response_time 0.005, 0.008 msec 1663773797.354 request_time 0.012
So basically it seems to call https://api-somewebsite.com/àpi/somedata which does not exist and thus return 502 error.
I have read that with the trailing / the /api/ part should be well removed automatically. But it does not work. So I tried to rewrite it by myself:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
rewrite ^/api/(.*) /$1 break;
}
Still no luck.
I ended up trying some stuff found on the web but that I do not fully understand... like adding proxy_redirect instruction:
location /api/ {
proxy_pass https://api-somewebsite.com/;
access_log /var/log/nginx/upstream.log upstreamlog;
rewrite ^/api/(.*) /$1 break;
proxy_redirect https://api-somewebsite.com/ /api/;
}
Well, I feel that I lack some basic stuff to make it work, but I cannot find what. Any insights would be greatly appreciated.
====== EDIT 1 ======
According to Stephen Dunne answer, i tried to add an upstream for the server.
Here is my edited code:
upstream magiceden {
server api-mainnet.magiceden.dev:443 max_fails=0;
zone magiceden-api 64k;
keepalive 60;
}
server {
server_name genoverse.me www.genoverse.me;
location / {
root /home/hcomere/genoverse.me;
index index.html;
}
location /magiceden_api/ {
proxy_pass https://magiceden/;
access_log /var/log/nginx/access_magiceden.log upstreamlog;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/genoverse.me/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/genoverse.me/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
}
I still have error 502 - Bad Gateway - when visiting https://www.genoverse.me/magiceden_api/
where i should get an error 400 - Not found - from the api provider
https://api-mainnet.magiceden.dev/
====== EDIT 2 ======
Oh well, i discovered that browsers have a redirect cache, this explain why sometimes things did not work where they should work.
Once i cleared the redirect cache after each config modification, things were way more smooth and understandable !...
I think the issue here is that you are using a Uri and not an upstream.
I have read that with the trailing / the /api/ part should be well removed automatically.
This is correct.
Try adding an upstream for the server.
upstream somesite {
server api-somewebsite.com:443 max_fails=0;
zone somesite-api 64k;
keepalive 60;
}
And then use the upstream in your location block (keeping the trailing slash)
location /api/ {
proxy_pass https://somesite/;
access_log /var/log/nginx/upstream.log upstreamlog;
}
Now when you browse to the /api location you should be redirected as expected.

How to redirect https://www.example.com to https://example.com with Nginx?

I have PHP webapplication running on a VPS, served by Nginx. It's already live, under https://thebedechkacase.com.
I have my SSL certificate setup automatically via Certbot. I want to have all my pages only to be accessible under the www-less domain and only via secure protocol (for SEO-reasons).
I already have some redirects in place in my Nginx config:
www.thebedechkacase.com redirects to https://thebedechkacase.com with a 301, same for http://thebedechkacase.com and http://www.thebedechkacase.com.
But if someone tries to access the site via https://www.thebedechkacase.com, they are met with Warning: Potential Security Risk Ahead error message from the browser (which is understandable since I don't have a wildcard certificate, so the www sub-domain is not included).
What I would like to do is to redirect also https://www.thebedechkacase.com/* to https://thebedechkacase.com/*.
Currently my Nginx config looks like this:
server {
# Path to the application
root /var/www/thebedechkacase.com/public;
server_name thebedechkacase.com;
location / {
# try to serve file directly, fallback to index.php
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\.php(/|$) {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
# optionally set the value of the environment variables used in the application
# fastcgi_param APP_ENV prod;
# fastcgi_param APP_SECRET <app-secret-id>;
# fastcgi_param DATABASE_URL "mysql://db_user:db_pass#host:3306/db_name";
# When you are using symlinks to link the document root to the
# current version of your application, you should pass the real
# application path instead of the path to the symlink to PHP
# FPM.
# Otherwise, PHP's OPcache may not properly detect changes to
# your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126
# for more information).
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/index.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}
# SSL settings automatically added by Certbot
listen [::]:443 ssl http2 ipv6only=on; # managed by Certbot
listen 443 ssl http2; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/thebedechkacase.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/thebedechkacase.com/privkey.pem; # managed by Certbot
# Commented out because HTTP2 needs newer chipers
# include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
# Define the allowed chipers
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# return 404 for all other php files not matching the front controller
# this prevents access to other php files you don't want to be accessible.
location ~ \.php$ {
return 404;
}
# Don't serve .htaccess files
location ~ /\.ht {
deny all;
}
# Disable PHP execution for upload directory
location /public/uploads/ {
location ~ \.php$ {return 403;}
}
# Turn on Gzip
gzip on;
# Make sure images js css are always gzipped
gzip_types application/javascript image/* text/css;
gunzip on;
# Expire rules for static content
# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
expires -1; # Don't cache
}
# Media: images, icons, video, audio
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|webp|gz|svg|svgz|mp4|ogg|ogv|webm)$ {
expires 1M; # One month
access_log off;
add_header Cache-Control "private";
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
expires 1y; # One year
access_log off;
add_header Cache-Control "private";
}
}
server {
listen 80 default_server;
listen [::]:80 default_server;
# Redirect HTTP to HTTPS
if ($host = thebedechkacase.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name thebedechkacase.com;
return 404; # managed by Certbot
# redirect all requests to HTTPS
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
}
# Redirect all www to non-www
server {
server_name www.thebedechkacase.com;
return 301 $scheme://thebedechkacase.com$request_uri;
}
server {
server_name https://www.thebedechkacase.com;
return 301 $scheme://thebedechkacase.com$request_uri;
}
As you can see I have two server block at the end that take care of redirecting http to https and one that redirects www to non-www.
But why are these not working for the mentioned https://www.thebedechkacase.com scenario?

nginx: [emerg] invalid port in url "https://x.x.x.x./live/rtmp/auth"?

I am getting this message after changing my auth url to https. Is there a way to change callback to https or is it not supported for on_publish directive ? FYI - ngixn is ssl enabled.
I don't know if you have solved the problem, but I have encountered the same one. In researching, it seems that the on_* directives do not support secure connections.
So I tried to work around the problem by serving my web application locally in http like this:
/etc/nginx/sites-available/yourdomain.conf :
rtmp {
server {
listen 1935;
chunk_size 4096;
application live {
deny play all;
record off;
live on;
on_publish http://127.0.0.1:8080/api/stream;
on_done http://127.0.0.1:8080/api/stream/end;
}
}
}
/etc/nginx/nginx.conf :
server {
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
root /var/www/html/myapp/public;
index index.html index.php;
server_name yourdomain.com www.yourdomain.com;
# rest of your config...
}
# then, serve your app on localhost for call api locally with http from on_* directives
server {
listen 8080;
listen [::]:8080;
server_name 127.0.0.1;
root /var/www/html/myapp/public;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.0-fpm.sock;
}
}
If it helps others :)

Nginx reverse proxy doesn't work as expected

I have two domains on different nginx(1.15.0) servers (server1 example.com and server2 example.net). I've tried to set up server2 as a reverse proxy with ngx_http_substitutions_filter_module but it doesn't work as expected.
Due to my config, subs_filter directive should replace example.com to example.net but when I type example.net in browser it redirects me to example.com.
nginx.conf
http {
//other settings
.....
include /etc/nginx/sites-enabled/*;
upstream example.com {
server example.com;
}
}
example.net.conf
server {
listen 80;
server_name example.net www.example.net;
rewrite ^/(.*)$ https://example.net/$1 permanent;
}
server {
listen 443 ssl;
server_name example.net;
ssl_certificate /etc/letsencrypt/live/example.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.net/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
root html;
try_files $uri #example.com;
}
location #example.com {
include replace.conf;
proxy_pass http://example.com;
proxy_cookie_domain example.com example.net;
proxy_set_header Accept-Encoding "";
proxy_set_header Host example.com;
proxy_redirect http://example.com http://example.net;
}
}
replace.conf
# replace direct links
subs_filter "www.example.com" "example.net" gi;
subs_filter "example.com" "example.net" gi;
Seems like nginx ignores subs_filter directive.
Could someone explain me how can I replace uri properly using ngx_http_substitutions_filter_module? Thank you for advice!
Problem solved.
First of all I removed upstream from nginx.conf:
upstream example.com {
server example.com;
}
Then I changed following lines in example.net.conf:
location / {
...
try_files $uri #static;
}
location #static {
...
proxy_pass https://example.com;
...
...
...
proxy_redirect https://example.com https://example.net;
}
All works fine except login form. Firefox works correctly but Chrome returns error 422. I suppose this is because the login form works on javascript.
Anyway thanks to all!

NGINX Rewrite single HTTPS URL to HTTP

On my NGINX server, I have all non-SSL traffic redirected to my SSL site.
Now, I want to have a single URL excluded from this, specifically:
https://pyronexus.com/forum/pages.php and everything appended to pages.php, such as pages.php?page=blahblah redirected to http://pyronexus.com/forum/pages.php, etc.
My config file looks like this so far, but I've not had any luck in getting my rewrite for this single url to work.
server {
server_name
www.pyronexus.com
;
listen 80 default;
listen 443 ssl;
ssl_certificate ssl/pyronexus.com.crt;
ssl_certificate_key ssl/pyronexus.com.key;
return 301 https://pyronexus.com$request_uri;
}
server {
server_name
pyronexus.com
;
listen 80;
listen 443 default ssl;
ssl_certificate ssl/pyronexus.com.crt;
ssl_certificate_key ssl/pyronexus.com.key;
root /home/nginx/pyronexus.com/public;
index index.html index.php;
access_log /home/nginx/pyronexus.com/logs/access.log;
error_log /home/nginx/pyronexus.com/logs/error.log;
include php.conf;
include mime.types;
location /forum/ {
#include pyronexus-naxsi.rules;
rewrite ^/forum/forum-([0-9]+)\.html$ /forum/forumdisplay.php?fid=$1;
rewrite ^/forum/forum-([0-9]+)-page-([0-9]+)\.html$ /forum/forumdisplay.php?fid=$1&page=$2;
rewrite ^/forum/thread-([0-9]+)\.html$ /forum/showthread.php?tid=$1;
rewrite ^/forum/thread-([0-9]+)-page-([0-9]+)\.html$ /forum/showthread.php?tid=$1&page=$2;
rewrite ^/forum/thread-([0-9]+)-lastpost\.html$ /forum/showthread.php?tid=$1&action=lastpost;
rewrite ^/forum/thread-([0-9]+)-nextnewest\.html$ /forum/showthread.php?tid=$1&action=nextnewest;
rewrite ^/forum/thread-([0-9]+)-nextoldest\.html$ /forum/showthread.php?tid=$1&action=nextoldest;
rewrite ^/forum/thread-([0-9]+)-newpost\.html$ /forum/showthread.php?tid=$1&action=newpost;
rewrite ^/forum/thread-([0-9]+)-post-([0-9]+)\.html$ /forum/showthread.php?tid=$1&pid=$2;
rewrite ^/forum/post-([0-9]+)\.html$ /forum/showthread.php?pid=$1;
rewrite ^/forum/announcement-([0-9]+)\.html$ /forum/announcements.php?aid=$1;
rewrite ^/forum/user-([0-9]+)\.html$ /forum/member.php?action=profile&uid=$1;
rewrite ^/forum/calendar-([0-9]+)\.html$ /forum/calendar.php?calendar=$1;
rewrite ^/forum/calendar-([0-9]+)-year-([0-9]+)\.html$ /forum/calendar.php?action=yearview&calendar=$1&year=$2;
rewrite ^/forum/calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)\.html$ /forum/calendar.php?calendar=$1&year=$2&month=$3;
rewrite ^/forum/calendar-([0-9]+)-year-([0-9]+)-month-([0-9]+)-day-([0-9]+)\.html$ /forum/calendar.php?action=dayview&calendar=$1&year=$2&month=$3&day=$4;
rewrite ^/forum/calendar-([0-9]+)-week-(n?[0-9]+)\.html$ /forum/calendar.php?action=weekview&calendar=$1&week=$2;
rewrite ^/forum/event-([0-9]+)\.html$ /forum/calendar.php?action=event&eid=$1;
rewrite ^/forum/archive/index\.php/forum-([0-9]+)\.html$ /forum/archive/index.php?forum-$1.html;
rewrite ^/forum/archive/index\.php/thread-([0-9]+)\.html$ /forum/archive/index.php?thread-$1.html;
}
location ~ /forum/(inc) {
deny all;
}
}
The rewrite rule I have tried is this, but I'm still getting to grips on how these rules work:
rewrite ^https://pyronexus.com/forum/pages\.php(.*)$ http://pyronexus.com/forum/pages.php$1;
Open up the configuration for your site, mine is /etc/nginx/sites-enabled/pyronexus.com.
Add the following server directive, adjusting the variables as needed:
server {
server_name
www.your-site.com
;
listen 80;
listen 443 ssl;
ssl_certificate ssl/your-certificate.crt;
ssl_certificate_key ssl/your-certificate.key;
return 301 https://your-site.com$request_uri;
}
This directive will force any www connections, be it through SSL or non-SSL, to non-www.
Add another directive. Although in this directive you can add any exclusions of pages you don’t want to be SSL-enabled. Add them before the location ~ / {} directive (I’ve included an example in there, which excludes http://your-site.com/forum/pages.php from HTTPS connections):
server {
server_name
your-site.com
;
listen 80 default;
root /your/site/root;
access_log /your/logs/location/access.log;
error_log /your/logs/location/error.log;
include global.conf;
# This excludes forum/pages.php from being forced through HTTPS
location ~ ^/forum/pages\.php$ {
include php.conf;
}
# This will force any http:// connections through https://
location ~ / {
return 301 https://your-site.com$request_uri;
}
}
Add a third, and final directive. This one is the directive that handles all SSL connections. You’ll need to put any exclusions you put above in here as well, and redirect people to a http connection:
server {
server_name
your-site.com
;
listen 443 default ssl;
ssl_certificate ssl/your-site.crt;
ssl_certificate_key ssl/your-site.key;
root /your/site/root;
access_log /your/logs/location/access.log;
error_log /your/logs/location/error.log;
include global.conf;
# This will force forum/pages.php through http://
location ~ ^/forum/pages\.php$ {
return 301 http://your-site.com$request_uri;
}
include php.conf;
}
That’s it! Test your configuration out!
If you’re wondering what’s in my global.conf and php.conf, then here they are:
global.conf:
# Tries to access the file directly before handing over to index.php
location / {
try_files $uri $uri/ /index.php?$args;
}
# Exclude common static file formats from logging and cache as long as possible
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|txt)$ {
access_log off;
log_not_found off;
expires max;
}
# Deny access to files that start with a dot, such as .htaccess
location ~ /\. {
deny all;
}
# Deny access to php files in folders named uploads and files (this is to prevent people uploading php files and executing them)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
php.conf:
# Pass all php files to php5-fpm
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
}
Source: https://pyronexus.com/blog/2015/01/11/nginx-remove-www-and-force-ssl-connections/

Resources