Open kanadgodse-lh opened 2 years ago
@heroku/languages Could someone take a look at this? Making it easier for people to migrate from the static buildpack will help with Heroku-22 adoption, and thus also with Heroku-20 EOL (when that time comes) :-)
@kanadgodse-lh , if you cat the ruby files in question
~ $ cat /app/bin/config/lib/ngx_mruby/headers.rb
# ghetto require, since mruby doesn't have require
eval(File.read('/app/bin/config/lib/nginx_config_util.rb'))
USER_CONFIG = "/app/static.json"
config = {}
config = JSON.parse(File.read(USER_CONFIG)) if File.exist?(USER_CONFIG)
req = Nginx::Request.new
uri = req.var.uri
if config["headers"]
config["headers"].to_a.reverse.each do |route, header_hash|
if Regexp.compile("^#{NginxConfigUtil.to_regex(route)}$") =~ uri
header_hash.each do |key, value|
# value must be a string
req.headers_out[key] = value.to_s
end
break
end
end
end
~ $ cat /app/bin/config/lib/ngx_mruby/routes_fallback.rb
# ghetto require, since mruby doesn't have require
eval(File.read('/app/bin/config/lib/nginx_config_util.rb'))
USER_CONFIG = "/app/static.json"
config = {}
config = JSON.parse(File.read(USER_CONFIG)) if File.exist?(USER_CONFIG)
req = Nginx::Request.new
uri = req.var.uri
proxies = config["proxies"] || {}
redirects = config["redirects"] || {}
if proxy = NginxConfigUtil.match_proxies(proxies.keys, uri)
"@#{proxy}"
elsif redirect = NginxConfigUtil.match_redirects(redirects.keys, uri)
"@#{redirect}"
else
"@404"
end
It seems to mostly be processing your cache-control headers you put in your static.json
file. I just removed the mruby lines from the nginx config file and dropped the $fallback variable from the try_files call.
@kanadgodse-lh , if you cat the ruby files in question
~ $ cat /app/bin/config/lib/ngx_mruby/headers.rb # ghetto require, since mruby doesn't have require eval(File.read('/app/bin/config/lib/nginx_config_util.rb')) USER_CONFIG = "/app/static.json" config = {} config = JSON.parse(File.read(USER_CONFIG)) if File.exist?(USER_CONFIG) req = Nginx::Request.new uri = req.var.uri if config["headers"] config["headers"].to_a.reverse.each do |route, header_hash| if Regexp.compile("^#{NginxConfigUtil.to_regex(route)}$") =~ uri header_hash.each do |key, value| # value must be a string req.headers_out[key] = value.to_s end break end end end
~ $ cat /app/bin/config/lib/ngx_mruby/routes_fallback.rb # ghetto require, since mruby doesn't have require eval(File.read('/app/bin/config/lib/nginx_config_util.rb')) USER_CONFIG = "/app/static.json" config = {} config = JSON.parse(File.read(USER_CONFIG)) if File.exist?(USER_CONFIG) req = Nginx::Request.new uri = req.var.uri proxies = config["proxies"] || {} redirects = config["redirects"] || {} if proxy = NginxConfigUtil.match_proxies(proxies.keys, uri) "@#{proxy}" elsif redirect = NginxConfigUtil.match_redirects(redirects.keys, uri) "@#{redirect}" else "@404" end
It seems to mostly be processing your cache-control headers you put in your
static.json
file. I just removed the mruby lines from the nginx config file and dropped the $fallback variable from the try_files call.
So I removed every line with mruby and every $fallback variable from my config/nginx.conf.erb that was created from using
$ heroku run bash ~ $ bin/config/make-config ~ $ cat config/nginx.conf
This was from inside the app that I removed the create-react-app-buildpack from and replaced with heroku-community/nginx. Somehow I got a build succeed but it's not rendering anything for me.
As a test @jamesmichiemo , can you slap a /index.html
on the end of your URL?
As a test @jamesmichiemo , can you slap a
/index.html
on the end of your URL?
Thank you @tylerjgarland for assisting! I'll try that change eventually but it feels like it would be worth more of my time if I tried the other alternative hosting providers listed on the create-react-app deployment docs and maybe telling them to remove Heroku from their documentation for now until the chaos dies.
Hi. I tried to follow the instructions regarding the mruby static logic.
I added node.js and nginx buildpack.
Deployed. The node build succeeded. The nginx didn't give any errors.
But when I visited the app https://invulnerable-maison-61218.herokuapp.com/ there is an app error.
In the server log is this.
2022-07-15T06:45:42.939892+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/" host=invulnerable-maison-61218.herokuapp.com request_id=5ad9be69-bdfb-4670-b73b-77d4ed89506f fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https
2022-07-15T06:45:43.797328+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/favicon.ico" host=invulnerable-maison-61218.herokuapp.com request_id=e85c496a-6723-4c4a-9149-8cd07ebde3b7 fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https
2022-07-15T06:45:47.687092+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/index.html" host=invulnerable-maison-61218.herokuapp.com request_id=469f0537-7db3-43b0-93d3-09b5dedfc325 fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https
2022-07-15T06:45:48.506074+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/favicon.ico" host=invulnerable-maison-61218.herokuapp.com request_id=9f9ed82a-0a53-4445-9b96-a57ba605ac45 fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https
Here is my config/nginx.conf.erb file which I generated based on another react app deployed on Heroku using the mars buildpack.
daemon off;
worker_processes auto;
events {
use epoll;
accept_mutex on;
worker_connections 512;
}
http {
gzip on;
gzip_comp_level 6;
gzip_min_length 512;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on;
gzip_proxied any;
server_tokens off;
access_log logs/access.log;
error_log stderr error;
include mime.types;
default_type application/octet-stream;
sendfile on;
#Must read the body in 5 seconds.
client_body_timeout 5;
server {
listen 38169 reuseport;
charset UTF-8;
port_in_redirect off;
keepalive_timeout 5;
root build/;
location / {
try_files $uri $uri/;
}
location ~ ^/.*$ {
set $route /.*;
try_files $uri $path ;
}
# need this b/c setting $fallback to =404 will try #{root}=404 instead of returning a 404
location @404 {
return 404;
}
# fallback proxy named match
# fallback redirects named match
}
}
Okay, I swapped the order of the two buildpacks and the app is working now.
Hi. I tried to follow the instructions regarding the mruby static logic.
I added node.js and nginx buildpack.
Deployed. The node build succeeded. The nginx didn't give any errors.
But when I visited the app https://invulnerable-maison-61218.herokuapp.com/ there is an app error.
In the server log is this.
2022-07-15T06:45:42.939892+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/" host=invulnerable-maison-61218.herokuapp.com request_id=5ad9be69-bdfb-4670-b73b-77d4ed89506f fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https 2022-07-15T06:45:43.797328+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/favicon.ico" host=invulnerable-maison-61218.herokuapp.com request_id=e85c496a-6723-4c4a-9149-8cd07ebde3b7 fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https 2022-07-15T06:45:47.687092+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/index.html" host=invulnerable-maison-61218.herokuapp.com request_id=469f0537-7db3-43b0-93d3-09b5dedfc325 fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https 2022-07-15T06:45:48.506074+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/favicon.ico" host=invulnerable-maison-61218.herokuapp.com request_id=9f9ed82a-0a53-4445-9b96-a57ba605ac45 fwd="221.124.121.128" dyno= connect= service= status=503 bytes= protocol=https
Here is my config/nginx.conf.erb file which I generated based on another react app deployed on Heroku using the mars buildpack.
daemon off; worker_processes auto; events { use epoll; accept_mutex on; worker_connections 512; } http { gzip on; gzip_comp_level 6; gzip_min_length 512; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_vary on; gzip_proxied any; server_tokens off; access_log logs/access.log; error_log stderr error; include mime.types; default_type application/octet-stream; sendfile on; #Must read the body in 5 seconds. client_body_timeout 5; server { listen 38169 reuseport; charset UTF-8; port_in_redirect off; keepalive_timeout 5; root build/; location / { try_files $uri $uri/; } location ~ ^/.*$ { set $route /.*; try_files $uri $path ; } # need this b/c setting $fallback to =404 will try #{root}=404 instead of returning a 404 location @404 { return 404; } # fallback proxy named match # fallback redirects named match } } @xiaopow I need to deploy a Vue application on heroku with the new buildpack, I tried this configuration and it didn't work.
@andersonar12 , did you create a web procfile?
Unfortunately, none of these examples works for me either, Heroku complains about the missing start
script. We use heroku-buildpack-static to deploy a storybook build folder and have no node server running.
What is unclear to me is whether we now need a web Procfile to start a (node) server? Did this buildback handle it before?
Cheers!
After much back and forth I finally got the migration working for us. React + vite. Two things to take notice of
web: bin/start-nginx-solo
mruby
in the config file and have to use environment variable for the port.
This is what I ended up with
daemon off;
worker_processes auto;
events { use epoll; accept_mutex on; worker_connections 512; }
http { gzip on; gzip_comp_level 6; gzip_min_length 512; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_vary on; gzip_proxied any;
server_tokens off; access_log logs/access.log; error_log stderr error; include mime.types; default_type application/octet-stream; sendfile on;
client_body_timeout 5;
server { listen <%= ENV["PORT"] %>; charset UTF-8; port_in_redirect off; keepalive_timeout 5; root /app/dist;
resolver 10.1.0.2 8.8.8.8;
# Allow payloads of up to 10mb
client_max_body_size 10M;
# Redirect all non-https traffic to https
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
location = /index.html {
add_header Cache-Control "no-store, no-cache";
add_header Strict-Transport-Security "max-age=31536002;";
try_files $uri $uri/ =404;
}
location / {
add_header 'Cache-Control' "public, max-age=3600";
try_files $uri $uri/ /index.html;
}
location /manifest.json {
add_header Cache-Control "no-store, no-cache";
add_header Access-Control-Allow-Origin "*";
try_files $uri $uri/ =404;
}
# Cache assets for a long time, since all of them get unique names on each build
location ~ ^/assets/[^/]*$ {
add_header Cache-Control "public, max-age=31536000";
add_header Access-Control-Allow-Origin "*";
try_files $uri $uri/ =404;
}
# Need this b/c setting $fallback to =404 will try #{root}=404 instead of returning a 404
location @404 {
return 404;
}
# Redirect all request on /api/* to backend server
set $api_endpoint '<%= "#{ENV['VITE_API_PROTOCOL']}://#{ENV['VITE_API_ENDPOINT']}" %>';
location /api/ {
rewrite ^/api//?(.*)$ /$1 break;
proxy_pass $api_endpoint;
proxy_ssl_server_name on;
proxy_redirect $api_endpoint/ /api/;
}
} }
This was migrated from `static.json`
```json
{
"root": "./dist",
"https_only": true,
"headers": {
"/**": {
"Strict-Transport-Security": "max-age=7776001"
},
"/": {
"Cache-Control": "no-store, no-cache",
"Strict-Transport-Security": "max-age=7776002"
},
"/assets/**": {
"Cache-Control": "public, max-age=31536000",
"Access-Control-Allow-Origin": "*"
},
"/manifest.json": {
"Cache-Control": "no-store, no-cache",
"Access-Control-Allow-Origin": "*"
}
},
"routes": {
"/assets/*": "/assets/",
"/**": "index.html"
},
"proxies": {
"/api/": {
"origin": "${VITE_API_PROTOCOL}://${VITE_API_ENDPOINT}"
}
}
}
After much back and forth I finally got the migration working for us. React + vite. Two things to take notice of
- you need to create a Procfile with
web: bin/start-nginx-solo
- Need to remove all mentions of
mruby
in the config file and have to use environment variable for the port. This is what I ended up withdaemon off; worker_processes auto; events { use epoll; accept_mutex on; worker_connections 512; } http { gzip on; gzip_comp_level 6; gzip_min_length 512; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; gzip_vary on; gzip_proxied any; server_tokens off; access_log logs/access.log; error_log stderr error; include mime.types; default_type application/octet-stream; sendfile on; # Must read the body in 5 seconds. client_body_timeout 5; server { listen <%= ENV["PORT"] %>; charset UTF-8; port_in_redirect off; keepalive_timeout 5; root /app/dist; resolver 10.1.0.2 8.8.8.8; # Allow payloads of up to 10mb client_max_body_size 10M; # Redirect all non-https traffic to https if ($http_x_forwarded_proto != "https") { return 301 https://$host$request_uri; } location = /index.html { add_header Cache-Control "no-store, no-cache"; add_header Strict-Transport-Security "max-age=31536002;"; try_files $uri $uri/ =404; } location / { add_header 'Cache-Control' "public, max-age=3600"; try_files $uri $uri/ /index.html; } location /manifest.json { add_header Cache-Control "no-store, no-cache"; add_header Access-Control-Allow-Origin "*"; try_files $uri $uri/ =404; } # Cache assets for a long time, since all of them get unique names on each build location ~ ^/assets/[^/]*$ { add_header Cache-Control "public, max-age=31536000"; add_header Access-Control-Allow-Origin "*"; try_files $uri $uri/ =404; } # Need this b/c setting $fallback to =404 will try #{root}=404 instead of returning a 404 location @404 { return 404; } # Redirect all request on /api/* to backend server set $api_endpoint '<%= "#{ENV['VITE_API_PROTOCOL']}://#{ENV['VITE_API_ENDPOINT']}" %>'; location /api/ { rewrite ^/api//?(.*)$ /$1 break; proxy_pass $api_endpoint; proxy_ssl_server_name on; proxy_redirect $api_endpoint/ /api/; } } }
This was migrated from
static.json
{ "root": "./dist", "https_only": true, "headers": { "/**": { "Strict-Transport-Security": "max-age=7776001" }, "/": { "Cache-Control": "no-store, no-cache", "Strict-Transport-Security": "max-age=7776002" }, "/assets/**": { "Cache-Control": "public, max-age=31536000", "Access-Control-Allow-Origin": "*" }, "/manifest.json": { "Cache-Control": "no-store, no-cache", "Access-Control-Allow-Origin": "*" } }, "routes": { "/assets/*": "/assets/", "/**": "index.html" }, "proxies": { "/api/": { "origin": "${VITE_API_PROTOCOL}://${VITE_API_ENDPOINT}" } } }
This is gold! Couldn't have done this without your help!
@adamalfredsson I run into the problem recently and after following all the steps here I got 502 bad gateway, don't know what to do next
Hello,
We have many production react apps and use this buildpack along with https://github.com/mars/create-react-app-buildpack
Since that buildpack and this one is also deprecated and the migration guide does not give details for the following step, I am stuck: Replace path logic that previously used
mruby
with static logic.Can someone please help by elaborating how to replace path logic with static logic?