lightweight go reverse proxy for ollama with bearer token authentication
go
proxy
ollama
1package main
2
3import (
4 "fmt"
5 "net/http"
6 "net/http/httputil"
7 "net/url"
8 "strings"
9)
10
11// authMiddleware validates Bearer token authorization
12func authMiddleware(token string) func(http.Handler) http.Handler {
13 return func(next http.Handler) http.Handler {
14 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15 authHeader := r.Header.Get("Authorization")
16 if authHeader == "" {
17 http.Error(w, "Unauthorized", http.StatusUnauthorized)
18 return
19 }
20
21 parts := strings.SplitN(authHeader, " ", 2)
22 if len(parts) != 2 || parts[0] != "Bearer" {
23 http.Error(w, "Unauthorized", http.StatusUnauthorized)
24 return
25 }
26
27 if parts[1] == "" || parts[1] != token {
28 http.Error(w, "Unauthorized", http.StatusUnauthorized)
29 return
30 }
31
32 next.ServeHTTP(w, r)
33 })
34 }
35}
36
37// newProxy creates a reverse proxy for the target URL
38func newProxy(targetURL string) (*httputil.ReverseProxy, error) {
39 if targetURL == "" {
40 return nil, fmt.Errorf("target URL cannot be empty")
41 }
42
43 target, err := url.Parse(targetURL)
44 if err != nil {
45 return nil, fmt.Errorf("invalid target URL: %w", err)
46 }
47
48 if target.Scheme == "" || target.Host == "" {
49 return nil, fmt.Errorf("invalid target URL: missing scheme or host")
50 }
51
52 proxy := httputil.NewSingleHostReverseProxy(target)
53
54 // Customize the request before sending to backend
55 originalDirector := proxy.Director
56 proxy.Director = func(req *http.Request) {
57 originalDirector(req)
58
59 // Remove proxy headers to make it look like a local request
60 req.Header.Del("X-Forwarded-For")
61 req.Header.Del("X-Forwarded-Host")
62 req.Header.Del("X-Forwarded-Proto")
63 req.Header.Del("Via")
64 req.Header.Del("Authorization")
65
66 // Set Host to the target host to make it appear local
67 req.Host = target.Host
68 }
69
70 return proxy, nil
71}