<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Santiago Morales</title>
    <description>The latest articles on DEV Community by Santiago Morales (@sandmor).</description>
    <link>https://dev.to/sandmor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1102318%2F826ce717-c096-48f7-a2bc-a31c1116d681.jpg</url>
      <title>DEV Community: Santiago Morales</title>
      <link>https://dev.to/sandmor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sandmor"/>
    <language>en</language>
    <item>
      <title>Bifrost and Bloated Headers: My Journey Setting Up an AI Gateway</title>
      <dc:creator>Santiago Morales</dc:creator>
      <pubDate>Fri, 05 Jun 2026 15:18:33 +0000</pubDate>
      <link>https://dev.to/sandmor/bifrost-and-bloated-headers-my-journey-setting-up-an-ai-gateway-ono</link>
      <guid>https://dev.to/sandmor/bifrost-and-bloated-headers-my-journey-setting-up-an-ai-gateway-ono</guid>
      <description>&lt;p&gt;Recently, I was trying to set up an AI gateway. I wasn't very familiar with Bifrost before but it caught my eye that it was written in go, a language that I have come to love and see as part of the future of server systems.&lt;/p&gt;

&lt;p&gt;In any case, after choosing Bifrost, I encountered my first hurdle. There were two ways to configure it, either by configuration file or by UI. In cases like this I'll usually go for the configuration file, I find pretty straightforward to have a YAML file carrying a exact definition of the configuration that I can then set in another environment if needed.&lt;/p&gt;

&lt;p&gt;However, in this case I went with UI, why? Because I wasn't very familiar with the tool, it is not as well known either so documentation may be scarce, and most importantly because I wanted to familiarize myself with its features, something that I can do more easily if I can explore a dashboard. Before taking this decision though, I made sure to inform myself if the UI was just basic and a configuration file was recommended for "advanced features." Thankfully, that didn't seem to be the case, according to the Bifrost documentation they offered first class UI support, though I was given to understand that some very niche features still may only be accessible through YAML.&lt;/p&gt;

&lt;p&gt;Choice made, I wrote a little docker compose file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;bifrost&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;maximhq/bifrost:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bifrost&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:8080:8080"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./bifrost-data:/app/data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And deployed it in a VPS. As you can see I am mapping to &lt;code&gt;127.0.0.1:8080&lt;/code&gt;, which makes sure that not other devices can access the insecure HTTP connection.&lt;/p&gt;

&lt;p&gt;With docker fired up, the next step was creating a configuration file in NGINX to expose this through a secure connection.&lt;/p&gt;

&lt;p&gt;NGINX configuration is one of those things that I have done many times and yet I always find myself looking up the exact syntax. The basics are simple enough, but getting location blocks and proxy headers exactly right comes with its own set of pitfalls that are easy to forget if you don't deal with them regularly.&lt;/p&gt;

&lt;p&gt;The first thing I needed was a domain name pointing to my VPS. I already had a subdomain ready for this, so I created an A record pointing to the server's IP address and waited for DNS propagation. That done, I created an NGINX server block for the subdomain, proxying through to Bifrost on port 8080.&lt;/p&gt;

&lt;p&gt;Importantly, I turned off proxy buffering (&lt;code&gt;proxy_buffering off;&lt;/code&gt;). When you're streaming model responses chunk by chunk, NGINX's default buffering can introduce lag that breaks the real-time feel.&lt;/p&gt;

&lt;p&gt;My initial NGINX configuration looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;bifrost.mydomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the server block configured and buffering disabled, I was ready to add TLS. I already had certbot installed, so granting my new subdomain a SSL certificate and configuring it in NGINX could be done easily with a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; bifrost.mydomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command both issues the certificate and updates NGINX configuration file to use it (changing port 80 to 443 and adding the SSL paths). With TLS in place, I could finally access the Bifrost dashboard through a secure connection. Opening the browser and navigating to my subdomain, I was greeted with a clean, minimal interface.&lt;/p&gt;

&lt;p&gt;The first that I noticed was that I wasn't prompted to create a first user or authentication at all, that is not gonna fly, was the first thing that I thought. As I was quite excited to test my gateway and didn't want to sift through the large interface, I quickly asked an AI assistant who didn't seem very familiar with the application as its first response was setting the dashboard behind HTTP Basic Auth.&lt;/p&gt;

&lt;p&gt;I have to admit that I toyed with the idea for a minute, until I just decided to check if there was an option built-in in Bifrost dashboard. Which was! Buried in Settings -&amp;gt; Security there as a way to set a password to the dashboard, though by the time of writing this article it says to be in beta.&lt;/p&gt;

&lt;p&gt;Once I set a username and password, and confirmed the change, the page reloaded and I found myself confronted by a login form. Filling up the credentials prove easy enough and now I have my dashboard secure.&lt;/p&gt;

&lt;p&gt;Next step was setting up a provider, and I thought this was going to be easy, but of course, nothing is ever that straightforward when you're trying a new tool.&lt;/p&gt;

&lt;p&gt;After configuring my first provider, a custom one. I noticed quickly that Bifrost showed a error indicator, most likely of failing to try and list the available models.&lt;/p&gt;

&lt;p&gt;But as it didn't show more information, I decided to try and call the API endpoint to see what would Bifrost do with this faulty provider.&lt;/p&gt;

&lt;p&gt;Digging a bit in how it should work by default, the convention was to call the api with a model in the format provider/model, so I did that using curl and immediately getting a concerning answer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"is_bifrost_error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"error when reading response headers: small read buffer. Increase ReadBufferSize. Buffer size=4096, contents: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nAccess-Control-Allow-Headers: Content-Type, Authorization, x-api-key, x-request-id, x-client, x-app, x-billing-mode, x-test-billing-mode, x-payment, x-x402, x-x402-payment-id, x-pr&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; application/json&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nDate: Fri, 30 May 2026 21:15:53 GMT&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nReferrer-Policy: strict-origin-when-cross-origin&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nServer: Vercel&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nStrict-Transport-Security: max-age=63072000&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;r&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nVary: rsc, next-router-state-tree&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"failed to execute HTTP request to provider API"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"extra_fields"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"original_model_requested"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"moonshotai/kimi-k2.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"resolved_model_used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"moonshotai/kimi-k2.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"request_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"chat_completion"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was just trying to configure my first provider and I was already getting a error! It seems like whatever Go library that Bifrost is using to handle HTTP has a buffer size of 4096 bytes for requests, and my provider was sending a bit more than that.&lt;/p&gt;

&lt;p&gt;Given the fields I figured out that my most likely suspect was &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt;, its value must be massive but actually not needed for our purposes. Therefore stripping it should fix the problem, right?&lt;/p&gt;

&lt;p&gt;Given that I'm already using NGINX, I could simply add a proxy layer to strip the CORS headers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;8081&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;host.docker.internal&lt;/span&gt; &lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;resolver&lt;/span&gt; &lt;span class="mf"&gt;8.8&lt;/span&gt;&lt;span class="s"&gt;.8.8&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="s"&gt;.1.1&lt;/span&gt; &lt;span class="s"&gt;valid=300s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;resolver_timeout&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;$upstream&lt;/span&gt; &lt;span class="s"&gt;https://myprovider.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="nv"&gt;$upstream$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_ssl_server_name&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_ssl_name&lt;/span&gt; &lt;span class="s"&gt;myprovider.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="s"&gt;myprovider.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# Strip theCORS headers that are crashing Bifrost&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_hide_header&lt;/span&gt; &lt;span class="s"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_hide_header&lt;/span&gt; &lt;span class="s"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_hide_header&lt;/span&gt; &lt;span class="s"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_hide_header&lt;/span&gt; &lt;span class="s"&gt;Access-Control-Expose-Headers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;proxy_pass_request_headers&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secondary proxy added, I needed to update and restart my docker compose file for Bifrost to be able to reach it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;    &lt;span class="na"&gt;extra_hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:host-gateway"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this I expected it to work, but sadly, I met another error, as registered in NGINX logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;2026/05/31&lt;/span&gt; &lt;span class="nf"&gt;17&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;54&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="s"&gt;[error]&lt;/span&gt; &lt;span class="mi"&gt;202599&lt;/span&gt;&lt;span class="c1"&gt;#202599: *25120 upstream sent too big header while reading response header from upstream, client: 172.19.0.2, server: host.docker.internal, request: "POST /v1/chat/completions HTTP/1.1", upstream: "https://215.151.1.1:443/v1/chat/completions", host: "host.docker.internal:8081"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apparently NGINX was also suffering from the same problem than Bifrost, the response headers from the provider were too large for its default buffer sizes. The fix was straightforward though, NGINX lets us tune these limits with a couple of directives. I added &lt;code&gt;proxy_buffer_size 32k;&lt;/code&gt; to my server block, giving it enough room to handle those large headers without choking.&lt;/p&gt;

&lt;p&gt;With the buffer sizes increased, I restarted NGINX and tried my curl request again. And it failed again! Checking the NGINX logs I found this new message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;2026/05/31&lt;/span&gt; &lt;span class="nf"&gt;17&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="s"&gt;[error]&lt;/span&gt; &lt;span class="mi"&gt;256520&lt;/span&gt;&lt;span class="c1"&gt;#256520: *25172 upstream sent too big header while reading response header from upstream, client: 13.212.191.221, server: bifrost.mydomain.com, request: "POST /v1/chat/completions HTTP/1.1", upstream: "http://127.0.0.1:8080/v1/chat/completions", host: "bifrost.mydomain.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This error is very similar to the previous one, however I immediately notice how it is pointing to my client and the domain that I gave the proxy. Not the provider, strange but this just means that now is Bifrost who is sending a large response to the client. I'm not sure if that means that it is passing through other headers from the providers that may be engorging the response, but I found easily enough to also bump up the buffer sizes of the main Bifrost server block as well. Same directive, &lt;code&gt;proxy_buffer_size 32k;&lt;/code&gt;, this time applied to the server block handling the connection between the outside world and Bifrost itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;bifrost.mydomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8080&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;# Increase buffer size strictly for reading large upstream headers&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_buffer_size&lt;/span&gt; &lt;span class="mi"&gt;32k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_read_timeout&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# SSL certificates managed by Certbot...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After reloading NGINX one more time, I sent my curl request and finally got a proper response back. The model answered without errors, and Bifrost successfully proxied the request through to my custom provider. A satisfactory victory after all the unexpected trouble that I went through, even if it stings me a bit that I had to patch things up to make it work.&lt;/p&gt;

&lt;p&gt;With the provider working I now have to secure the LLM endpoint so it couldn't be prompted from Bifrost gateway without a key. Setting a key in Bifrost was easy enough, though I have to dig a bit to find the option to disable keyless inference.&lt;/p&gt;

&lt;p&gt;Once I found that toggle and switched it off, I tested the endpoint again without passing an API key and was met with a proper authentication error instead of a successful response. That was reassuring.&lt;/p&gt;

&lt;p&gt;Adding a second provider turned out to be smoother than the first, probably because I had already dealt with the NGINX buffering issues and knew what to expect. I set up OpenAI as my second provider, which being a first-class citizen in Bifrost meant no custom proxy shenanigans were needed. The dashboard had a dedicated section for it, I plugged in my API key, and Bifrost immediately recognized it without any errors. A refreshing contrast to my earlier experience.&lt;/p&gt;

&lt;p&gt;Satisfied with the setup, I took a step back and reviewed what I had built. A Bifrost instance running in Docker, behind NGINX with TLS, two providers configured, the dashboard secured with authentication, and the inference endpoint protected by API keys. There were still things I could improve, experimenting with dynamic routing, configuring rate limits, maybe exploring some of those niche features that only the YAML configuration exposes, but the core functionality was there and working.&lt;/p&gt;

&lt;p&gt;For now, that was enough. The gateway was up, it was secure, and it was routing requests the way I wanted.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>go</category>
      <category>infrastructure</category>
    </item>
  </channel>
</rss>
