The most basic config with SSL from local CA

Are you using our SaaS platform (Baserow.io) or self-hosting Baserow?

Self-hosted

If you are self-hosting, what version of Baserow are you running?

Version 2.0.2

If you are self-hosting, which installation method do you use to run Baserow?

Docker version 29.0.4 on Ubuntu minimal server 24.04.2.

What are the exact steps to reproduce this issue?

Hi!
I already spent a lot of time over past 5 days, still without results, maybe could someone assist me?
I need: fully isolated on-prem with SSL from internal CA over HTTPS (QUIC is blocked).

What I worked on so far:
sudo docker run -d --name baserow -e BASEROW_PUBLIC_URL=https://plmurbaserow -e EMAIL_SMTP=True -e EMAIL_SMTP_HOST=smtp.[domain].com -v baserow_data:/baserow/data -v /opt/baserow/certs:/baserow/certs:ro -v /opt/baserow/caddy/Caddyfile:/baserow/caddy/Caddyfile:ro -p 443:443 -p 80:80 --restart unless-stopped baserow/baserow:2.0.2

Within certs folder, I have fullchain.pem and privkey.pem. I don’t think they are loaded by default, so I also replaced Caddyfile to include them (basically the original one, with addition of tls on the top):

https://plmurbaserow {
tls /baserow/certs/fullchain.pem /baserow/certs/privkey.pem
}

Current status is that http page opens (why?) but registering admin user results in “Could not connect to the API server”. Https is a blank page.

To clarify - baserow works fine, if I unbind the Caddyfile and create the container for http only. I already created my first “app” via http and I’m happy with the results. But I’ll need https, definitely. Full caddyfile I tried is:

{
on_demand_tls {
ask {$PRIVATE_BACKEND_URL:localhost:8000}/api/builder/domains/ask-public-domain-exists/
}

{$BASEROW_CADDY_GLOBAL_CONF}

}
https://plmurbaserow {
tls /baserow/certs/fullchain.pem /baserow/certs/privkey.pem
}

{$BASEROW_CADDY_ADDRESSES} {
tls {
on_demand
}

@is_baserow_tool {
    expression "{$BASEROW_PUBLIC_URL}".contains({http.request.host})
}

handle @is_baserow_tool {
    handle /api/* {
        reverse_proxy {$PRIVATE_BACKEND_URL:localhost:8000}
    }

    handle /ws/* {
        reverse_proxy {$PRIVATE_BACKEND_URL:localhost:8000}
    }

    handle /mcp/* {
        reverse_proxy {$PRIVATE_BACKEND_URL:localhost:8000}
    }

    handle /assistant/* {
        reverse_proxy {$PRIVATE_BACKEND_URL:localhost:8000}
    }

    handle_path /media/* {
        @downloads {
            query dl=*
        }
        header @downloads Content-disposition "attachment; filename={query.dl}"

        # Allow to call head from public url to get size
        header {
            Access-Control-Allow-Origin {$BASEROW_PUBLIC_URL:http://localhost}
            Access-Control-Allow-Methods "GET, HEAD, OPTIONS"
            Access-Control-Allow-Headers "*"
            Access-Control-Expose-Headers "Content-Length, Content-Type"
        }

        file_server {
            root {$MEDIA_ROOT:/baserow/media/}
        }
    }

    handle_path /static/* {
        file_server {
            root {$STATIC_ROOT:/baserow/static/}
        }
    }
}

reverse_proxy {$PRIVATE_WEB_FRONTEND_URL:localhost:3000}

}

This Saturday, “thanks to” Copilot, i was able to get it to run somehow with several modifications of this Caddyfile. Unfortunately, I then stumbled upon the next issue, which was this QUIC dependency. And during our attempts to disable QUIC, I lost my previously working config for HTTPS, failed it’s step-by-step recreation too.

So now, there are two requests within - First being, is there a verified, working solution for SSL certificate signed by internal CA, tutorial-wise? I found none, unfortunately, and I can’t get Caddy to provide me with a certificate, as it has to be in Internet-less productional network.

And the second question, that I also found no mentions on community, can we somehow disable HTTPS3/QUIC protocol, to rely only on standard HTTPS? Currently my cybersec team disallows use of that protocol, and I know we’re not alone on that matter. Since that’s fully isolated on-prem solution, I will probably be able to request an exception on the rule, but I believe it will be doable on Baserow, too.

Hey @izykopa

I haven’t verified every step, but this should work in your case:

1. SSL with Internal CA Certificates

When you’re using certificates signed by an internal CA (rather than a public CA like Let’s Encrypt), Caddy needs to be explicitly told to use your certificates instead of trying to obtain them automatically, as you did:

baserow.yourdomain.local {
    tls /etc/caddy/certs/cert.pem /etc/caddy/certs/key.pem

    reverse_proxy baserow:80
}

Then mount your certificates into the Caddy container in your docker-compose.yml:

caddy:
  volumes:
    - ./certs/cert.pem:/etc/caddy/certs/cert.pem:ro
    - ./certs/key.pem:/etc/caddy/certs/key.pem:ro

A few things to check:

  • The certificate file should contain the full chain (your server cert + intermediate CA certs)
  • The key file should be the private key corresponding to your server certificate
  • File permissions: Caddy needs read access to both files

2. Disabling QUIC/HTTP3

Yes, you can disable HTTP/3 (QUIC) in Caddy using the global options block. Add this at the top of your Caddyfile:

{
    servers {
        protocols h1 h2
    }
}

This restricts Caddy to HTTP/1.1 and HTTP/2 only — no QUIC traffic will be served.

Troubleshooting Tips

If you’re still having issues after applying this config:

  1. Check Caddy logs for certificate-related errors:

    docker logs <caddy-container-name>
    
  2. Verify your certificate chain is valid:

    openssl verify -CAfile /path/to/ca-root.pem /path/to/cert.pem
    
  3. Test the connection from a client that trusts your internal CA:

    curl -v https://baserow.yourdomain.local
    

I hope this helps.

Yess, that was it! I had a lot of issues with this Caddy config file after all my attempts, so I just recreated entire docker image and added lines from your hints, now they finally work!

Thank you!