I have a website hosted on Firebase, using static html, no server-side function is used to deliver the result.
When running curl -X PURGE https://mywebsite.com -v -L the result is:
{ "status": "ok", "id": "20755-1619059392-3560756" }
I need a way to restrict this action to specific IPs so that not anybody can reset my cache which might result in extra costs.
Also it seems that Firebase uses Varnish to manage cache (which is something am null at).
My client's security consultant sent us this recommendation on how to handle this issue, I'm not sure exactly if this is .htaccess syntax or what:
# Varnish recommends to using PURGE method only by valid user,
# for example by ip limiting and for other return 405 Not allowed:
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
# allow PURGE from localhost and 192.168.55...
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge);
}
}
I don't know how to apply this in Firebase Hosting, again am not using Server Functions, just the regular firebase.json with the following headers:
"headers": [
{
"source": "*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)",
"headers": [
{
"key": "Cache-Control",
"value": "public,max-age=31536000,immutable"
}
]
},
{
"source": "**/*.#(json|eot|otf|ttf|ttc|woff|font.css)",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
]
The following code is VCL code:
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
# allow PURGE from localhost and 192.168.55...
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge);
}
}
This code allows you to extend the behavior of Varnish. This code has to be added to your /etc/varnish/default.vcl file.
After adding this code to your VCL file, you have to reload your varnishd process to activate this VCL configuration.
If reloading varnishd is not an option, you can also activate the new VCL file using the following commands:
sudo varnishadm vcl.load purge_acl /etc/varnish/default.vcl
sudo varnishadm vcl.use purge_acl
For more information about Varnish and the VCL programming language, please have look at http://varnish-cache.org/docs/6.0/reference/index.html
There is no solution for the moment. This is the answer I received from the firebase support :
Hi Damien,
My name is Sergei, thanks for reaching out. I'll be assisting you.
The first thing to be addressed here is the fact that Varnish services
fall outside of our scope, so our information about its
implementations with our hosting services are not the most abundant.
Unfortunately, right now we can only control the caching behavior with
our existing tools.
I am sorry we cannot provide the functionality you need at the time,
if you would like to, we can submit the feature request so this is
visible to our engineering team.
Related
I created a simple Vue3 app, and I'm trying to call another local API (on a different port) on my machine. To better replicate the production server environment, I'm making a call to a relative API path. That means I need to use a proxy on the vite server to forward the API request to the correct localhost port for my local development. I defined my vite proxy like this in my vite.config.ts file:
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import basicSsl from '#vitejs/plugin-basic-ssl'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
basicSsl(),
vue()
],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
server: {
https: true,
proxy: {
'/api': {
target: 'https://localhost:44326', // The API is running locally via IIS on this port
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') // The local API has a slightly different path
}
}
}
});
I'm successfully calling my API from the Vue app, but I get this error in the command line where I'm running the vite server:
5:15:14 PM [vite] http proxy error:
Error: self signed certificate
at TLSSocket.onConnectSecure (node:_tls_wrap:1530:34)
at TLSSocket.emit (node:events:526:28)
at TLSSocket._finishInit (node:_tls_wrap:944:8)
at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:725:12)
I already tried to add the basic ssl package, and I don't particularly want to install the other NPM package that is in the top voted answer. Why does the vite server complain about a self signed certificate when I'm trying to call another API on my local machine? What can I do to fix this?
you could try secure: false
server: {
https: true,
proxy: {
'/api': {
target: 'https://localhost:44326', // The API is running locally via IIS on this port
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, '') // The local API has a slightly different path
}
}
}
the set of full options is available at https://github.com/http-party/node-http-proxy#options
Options
httpProxy.createProxyServer supports the following options:
target: url string to be parsed with the url module
forward: url string to be parsed with the url module
agent: object to be passed to http(s).request (see Node's https agent and http agent objects)
ssl: object to be passed to https.createServer()
ws: true/false, if you want to proxy websockets
xfwd: true/false, adds x-forward headers
secure: true/false, if you want to verify the SSL Certs
toProxy: true/false, passes the absolute URL as the path (useful for proxying to proxies)
prependPath: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
ignorePath: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).
localAddress: Local interface string to bind for outgoing connections
changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL
preserveHeaderKeyCase: true/false, Default: false - specify whether you want to keep letter case of response header key
auth: Basic authentication i.e. 'user:password' to compute an Authorization header.
hostRewrite: rewrites the location hostname on (201/301/302/307/308) redirects.
autoRewrite: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
protocolRewrite: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
cookieDomainRewrite: rewrites domain of set-cookie headers. Possible values:
false (default): disable cookie rewriting
String: new domain, for example cookieDomainRewrite: "new.domain". To remove the domain, use cookieDomainRewrite: "".
Object: mapping of domains to new domains, use "*" to match all domains.
For example keep one domain unchanged, rewrite one domain and remove other domains:
cookieDomainRewrite: {
"unchanged.domain": "unchanged.domain",
"old.domain": "new.domain",
"*": ""
}
cookiePathRewrite: rewrites path of set-cookie headers. Possible values:
false (default): disable cookie rewriting
String: new path, for example cookiePathRewrite: "/newPath/". To remove the path, use cookiePathRewrite: "". To set path to root use cookiePathRewrite: "/".
Object: mapping of paths to new paths, use "*" to match all paths.
For example, to keep one path unchanged, rewrite one path and remove other paths:
cookiePathRewrite: {
"/unchanged.path/": "/unchanged.path/",
"/old.path/": "/new.path/",
"*": ""
}
headers: object with extra headers to be added to target requests.
proxyTimeout: timeout (in millis) for outgoing proxy requests
timeout: timeout (in millis) for incoming requests
followRedirects: true/false, Default: false - specify whether you want to follow redirects
selfHandleResponse true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event
buffer: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option:
'use strict';
const streamify = require('stream-array');
const HttpProxy = require('http-proxy');
const proxy = new HttpProxy();
module.exports = (req, res, next) => {
proxy.web(req, res, {
target: 'http://localhost:4003/',
buffer: streamify(req.rawBody)
}, next);
};
I have a SPA with the following setup:
Frontend: React deployed using Firebase Hosting
Backend: GraphQL API written in Django deployed on Cloud Run
Everything works locally but when I deploy the app and try to make requests, I get a CORS error due to preflight missing allow origin header:
Access to fetch at 'https://cloud-run-api-hash.a.run.app/graphql/' from origin 'https://project-id.web.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Using django-cors-headers, I have already added the Firebase domain to the CORS_ORIGIN_WHITELIST in my Django settings.
My firebase.json looks like this:
{
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/authenticated/**",
"run": {
"serviceId": "cloud-run-serviceID",
"region": "us-central1"
}
},
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [ {
"source": "**/*.#(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
} ]
}
}
My intention is to trigger the cloud run container after the user is authenticated and is routed to https://project-id.web.app/authenticated, but I'm not seeing any Cloud Run logs after I login to the app. Furthermore, when I try to send any HTTP requests I get the CORS error shown above. Not sure where went wrong here because I strictly followed the Cloud Run/Firebase Hosting documentation. Any advice is greatly appreciated.
It turns out that the problem was with django-cors-headers. I put the allowed domains in CORS_ALLOWED_ORIGINS instead of CORS_ORIGIN_WHITELIST and it worked. According to the documentation, this setting was renamed. I still unsure why CORS_ORIGIN_WHITELIST doesn't work on Cloud Run though... it should work as an alias.
From Firebase docs, we get that it's supposed to set Cache-Control: private as default.
Firebase Hosting- Manage cache behavior
I generate my robots.txt on the fly, hence it might change from one request to the next. Because of that, I don't want it cached by the CDN. But to my surprise, I'm getting CDN hits for robots.txt.
See:
I do the same with ads.txt and sitemap.xml. The same is happening with ads.txt, but not with sitemap.xml.
Maybe it's something related to .txt files. Could this be a bug?
Do I have to explicitly set the Cache-Control: private?
You can configure that specific file's cache-control header through the firebase.json file like this:
{
"hosting": [
{
...,
"headers": [
{
"source": "robots.txt",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache"
}
]
}
]
}
]
}
More info in the docs here.
After authenticating, if I call any method, like os.compute().flavors().list() or os.images().list(), I get connect timed out. Why is this happening?
I set up a OpenStack with RDO packstack at a GoogleCloudsPlataform VM. I am doing auth with domain and project. Ive tried authing without project, and method calls did not timed out, but the responses were wrong, e.g, if I called list flavors, return none flavor.
If I do those calls with API endpoints, it works; if I auth with the same infos (user, pass, domain, project) and call flavors or images, it works.
Auth code:
OSClient.OSClientV3 os = OSFactory.builderV3()
.endpoint("http://host:5000/v3")
.credentials("admin", "pass", domain)
.scopeToProject(project)
.authenticate();
os.compute().flavors().list(); // "connection timed out" code
Endpoint auth call (that works):
curl -i \
-H "Content-Type: application/json" \
-d '
{ "auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": { "id": "default" },
"password": "pass"
}
}
},
"scope": {
"project": {
"name": "admin",
"domain": { "id": "default" }
}
}
}
}' \
"http://host:5000/v3/auth/tokens" ; echo
Endpoint images call:
curl -v -i -H "Content-Type: application/json" -H "X-Auth-Token:token" "http://host:8774/v2/images"; echo
In general, if you are getting timeouts on HTTP requests, the things to check are:
Are you using the correct hostname or IP address?
Are you using the correct port?
Is access being blocked by a firewall (somewhere)?
Is access being thwarted by misconfigured network routing (somewhere)?
Since you are using openstack4j, you can probably get more insights as to what is going on by turning on logging of the HTTP requests:
OSFactory.enableHttpLoggingFilter(true);
Check that it is sending requests to the V2 glance endpoint.
If that fails, use your IDE's Java debugger to figure out what requests are being sent to which service endpoints.
I want to use Firebase Hosting to host an angular application and I need to create a redirection to some old files in another URL.
According with the Firebase Documentation you can do basic redirections
"redirects": [ {
"source" : "/foo",
"destination" : "/bar",
"type" : 301
}, {
"source" : "/firebase/*",
"destination" : "https://www.firebase.com",
"type" : 302
} ]
But I need a wildcard redirection
"redirects": [ {
"source" : "/config/*",
"destination" : "//oldsiteurl/config/[match-request]",
"type" : 302
}]
So, basically I need that myapp.firebase.com/config/some.json redirects to //oldsiteurl/config/some.json. I have a lot of json files so I do not want to match file by file.
Did you know if this is possible?
Thanks!
For people landing on this page, it is now possible to have wildcards in the URLs:
Sometimes it is desirable to capture parts of the source URL of a redirect and re-use them in the destination. You can do this using a : prefix to identify the segment and an optional * after the name to indicate that it should capture the rest of the URL
(source)
"redirects": [
{
"source": "/subdomain/:random*",
"destination": "https://subdomain.myapp.com/:random*",
"type": 301
}
]
From the Firebase documentation on URL redirects (emphasis mine):
If a match is found, an HTTP redirect response is set with the "Location" header set to the static destination string, which can be a relative path or an absolute URL.
So it looks like the wild-carded part of the match is not carried over into the redirect.