CORS Proxy

Illustrated drawing of Amadeus Maxmimilian StadlerIllustrated drawing of Amadeus Maxmimilian Stadler

Amadeus Stadler

Published March 03, 2023

Unfortunately, as outlined in the article on limitations, many large Git providers don’t allow using Git from a browser at this point in time. To circumvent that, Mattrbld has to pipe requests through a proxy server.

In this article, you’ll learn how to host your own proxy server, so you can ensure your user’s privacy and reduce the load on the main proxy server.

What is CORS?

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.

Or in other words, CORS is a process that is used by web servers to control which other domains have access to resources through a browser. It does not affect server-to-server communication. This is why having a proxy server making the Git requests on Mattrbld’s behalf works.

How Does it Work?

When Mattrbld makes a Git request, it doesn’t contact the Git provider immediately, instead, it sends the request to the configured proxy server for the project, which then makes the request at the Git provider and sends back the data.

This workaround has some security and privacy concerns. Everything you do concerning your repository, including your authentication information, passes through that proxy server. If you’re not the one controlling it, or there is a security breach, a malicious actor could modify your requests or steal sensitive data!

If your project is using a Git provider such as Gogs or Gitea, you can simply leave the “CORS Proxy” field empty in the project configuration and things should work—however GitHub, GitLab, and Bitbucket still require a proxy server or an alternative solution if you want to work with Mattrbld.

To ensure privacy, stability, security and reliability you should use your own proxy server for anything except small projects with not a lot of files.

Setting Up a CORS Proxy

There are many ways to set up such a proxy, many web servers, such as Apache, are capable of doing it on their own, but if you have the ability to run Node.js, the simplest way is using the official @isomorphic-git/cors-proxy package on NPM. If you’d like to check how it works, feel free to read its source-code on GitHub.

Since the details of the setup vary depending on your hosting provider of choice, they’re not given here, but usually what you would want to do is have the proxy run on the local host of your server and pass requests to it via a reverse proxy setup that listens under a given route, for example /corsprox.

You can find more details in the README of @isomorphic-git/cors-proxy.

Using Apache

Here is an experimental configuration for an Apache webserver that proxies requests made to the /corsprox route via the mod_proxy module:

<VirtualHost *:1000>
  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/html

  # Enable SSL Proxy engine
  # so we can talk to https endpoints
  SSLProxyEngine on

  # Make sure ProxyRequests is off
  # for better security,
  # but mod_proxy needs to be enabled
  # for [P] to work in RewriteRule
  ProxyRequests Off

  # Unset the WWW-Authenticate header
  # to avoid browser login prompt on 401
  # if we’re making a proxy request
  Header unset "WWW-Authenticate" "expr=%{REQUEST_URI} =~ m#^/corsprox/#"

  # Since using ProxyPass
  # doesn't work, use mod_rewrite
  RewriteEngine on

  # This works but is dangerous
  # since it allows arbitratry requests
  # to be proxied through us
  # RewriteRule "^/corsprox/(.*$)" "https://$1" [P]

  # So instead, let's limit what can go through 
  # based on allow-requests.js
  # here: @isomorphic-git/cors-proxy
  # Since complex rewrite cond are hard to read 
  # we're repeating the RewriteRule
  # when appropriate
  # I believe the preflight requests never fire, 
  # since we’re not technically making a CORS 
  # request but I’ve added them nonetheless
  # isPreflightInfoRefs? or isInfoRefs?
  RewriteCond %{REQUEST_URI} "/info/refs$"
  RewriteCond %{QUERY_STRING} "(^|&)service=git-upload-pack($|&)" [OR]
  RewriteCond %{QUERY_STRING} "(^|&)service=git-receive-pack($|&)"
  RewriteRule "(.*$)" "$1" [R=200,L]

  # isInfoRefs?
  RewriteCond %{REQUEST_URI} "/info/refs$"
  RewriteCond %{QUERY_STRING} "(^|&)service=git-upload-pack($|&)" [OR]
  RewriteCond %{QUERY_STRING} "(^|&)service=git-receive-pack($|&)"
  RewriteRule "^/corsprox/(.*$)" "https://$1" [P]

  # isPreflightPull? or isPreflightPush?
  RewriteCond %{HTTP:Access-Control-Request-Headers} "(^|,\s*)content-type(,|$)"
  RewriteCond %{REQUEST_URI} "git-upload-pack$" [OR]
  RewriteCond %{REQUEST_URI} "git-receive-pack$"	
  RewriteRule "(.*$)" "$1" [R=200,L]

  # isPull?
  RewriteCond %{HTTP:Content-Type} "^application/x-git-upload-pack-request$"
  RewriteCond %{REQUEST_URI} "git-upload-pack$"
  RewriteRule "^/corsprox/(.*$)" "https://$1" [P]

  # isPush?
  RewriteCond %{HTTP:Content-Type} "^application/x-git-receive-pack-request$"
  RewriteCond %{REQUEST_URI} "git-receive-pack$"
  RewriteRule "^/corsprox/(.*$)" "https://$1" [P]

  # Fall back to index.html for routes
  # that don’t exist
  # (so client side router can pick up on them)
  FallbackResource  /index.html

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

Alternatives to Proxies

If you are self-hosting a GitLab instance on the same origin as Mattrbld, you should also be able to make Git requests without a proxy.

Somebody also made a Chrome extension that apparently can circumvent the CORS issues for GitLab. However, please note that using this extension is untested and neither officially endorsed nor supported.

Otherwise, you will likely need to switch to a Git provider that allows cross-origin Git requests.

This article concludes the section on hosting your own instance of Mattrbld and the CORS proxy server. You now know everything you need to effectively use Mattrbld for your own projects. Feel free to check the next section for some common troubleshooting steps in different scenarios—and build something great with Mattrbld. ✨