Skip to content

Caddy as a CORS proxy

Posted on:January 23, 2023 at 09:42 AM

CORS is a common issue when you are developing a web application. It is a security mechanism that restricts the resources you can access from another domain.

The usual solution is to contact the API provider and ask them to add your domain to the CORS whitelist. However, this is not always possible. For example, if you are using a third-party API, you may not be able to contact the API provider.

In this article, I will show you how to use Caddy as a (local) CORS proxy to bypass CORS issue.

Table of contents

Open Table of contents

Quick start

Install Caddy

You can install Caddy in many ways, see the official documentation for more details.

On macOS, you can simply run:

brew install caddy

Create a config file (Caddyfile)

Let’s assume that remote API host is https://robwu.nl, and local proxy we named cors.local. The Caddyfile should look like this:

(cors) {
        header {
                Access-Control-Allow-Origin "{http.request.header.Origin}"
                Access-Control-Allow-Credentials true
                Access-Control-Allow-Methods *
                Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization
        }
        @options {
                method OPTIONS
        }
        @not-options {
                not method OPTIONS
        }
}

cors.local {
        log {
                output file ./caddy-access.log
                level ERROR
        }
        respond @options 204
        reverse_proxy @not-options https://cors.local https://robwu.nl {
                header_up Host {upstream_hostport}
                header_up -X-Forwarded-Host
                header_up -X-forwarded-For
                header_up -X-forwarded-Proto
                header_down -Access-Control-Allow-Origin
        }
        import cors
}

Don’t forget to replace robwu.nl with the actual domain name.

Configure DNS & TLS

In order to be able to use a local custom domain name and HTTPS, you need to configure DNS and TLS.

Add the following line to /etc/hosts:

Usually you need to use sudo to edit this file.

127.0.0.1 cors.local

You also need to trust the local CA in order to use HTTPS, run the following command:

caddy trust

Run Caddy

Run Caddy in foreground:

caddy run

or, run Caddy in background:

caddy start
caddy stop

Now you can access the proxied API with CORS headers.

curl -v -H "Origin: http://127.0.0.1:3000" https://cors.local/dump.php

Known issues

  1. Sometimes, the response from the proxied API has duplicate CORS headers.