{"id":489,"date":"2026-09-23T08:30:00","date_gmt":"2026-09-23T06:30:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/?p=489"},"modified":"2026-10-26T11:17:35","modified_gmt":"2026-10-26T10:17:35","slug":"self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/","title":{"rendered":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy"},"content":{"rendered":"<p>Inference is the process of generating an answer from a model. A local language model can keep this processing on controlled hardware, but local hosting alone does not guarantee isolation, privacy compliance or cloud-level performance. Ollama\u2019s local API has no built-in authentication. A reverse proxy receives requests on behalf of Ollama, checks credentials and handles the encrypted TLS connection; network boundaries, outbound connections, storage and application behavior remain separate concerns.<\/p>\n<h2>1. The actual boundary<\/h2>\n<p>The example below exposes only a minimal generation endpoint through nginx. Loopback refers to the host\u2019s own local network address, 127.0.0.1 in this example. The proxy listens on the Docker host\u2019s IPv4 loopback address, not on every network interface. Remote use requires a separately designed VPN or private network entry point. The Ollama container has no published port. The Docker host and containers on the same backend network can still reach Ollama directly, so unrelated applications do not belong on that network.<\/p>\n<p>A normal Docker bridge permits outbound traffic. Model downloads therefore work, but this is not an air gap. <code>OLLAMA_NO_CLOUD=1<\/code> disables Ollama cloud features in supporting versions; a local model must still be selected. This setting does not block external tools, web UIs or host traffic. Strict offline operation needs controlled model provisioning and independently enforced outbound restrictions.<\/p>\n<figure class=\"lw-diagram\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/dia-489-ollama-20261024.png\" width=\"1120\" height=\"580\" alt=\"Only the proxy port is published on loopback. Backend-network access and outbound traffic remain separate controls.\"><figcaption>Only the proxy port is published on loopback. Backend-network access and outbound traffic remain separate controls.<\/figcaption><\/figure>\n<p>The network example assumes a current Docker Engine in standard NAT bridge mode. Docker documents loopback exposure to neighboring hosts in versions older than 28.0.0; custom direct-routing settings also require separate review.<\/p>\n<h2>2. Containers and certificates<\/h2>\n<p>The following <code>compose.yaml<\/code> is a starting configuration for CPU inference, not a complete enterprise deployment. <code>OLLAMA_IMAGE<\/code> and <code>NGINX_IMAGE<\/code> must contain reviewed image references, preferably immutable digests. Available memory, context length, model license and architecture need checking before model selection.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"yaml\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">YAML<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-yaml\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-attr\">services<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">ollama<\/span>:\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">image<\/span>: ${OLLAMA_IMAGE:?Set a reviewed Ollama image tag or digest}\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">restart<\/span>: unless-stopped\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">environment<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">OLLAMA_HOST<\/span>: 0.0.0.0:11434\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-attr\">OLLAMA_NO_CLOUD<\/span>: <span class=\"cbb-string\">\"1\"<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">volumes<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> ollama_data:\/root\/.ollama\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">networks<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> llm_backend\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">auth_proxy<\/span>:\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">image<\/span>: ${NGINX_IMAGE:?Set a reviewed nginx image tag or digest}\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">restart<\/span>: unless-stopped\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">ports<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> <span class=\"cbb-string\">\"127.0.0.1:8443:443\"<\/span>\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">volumes<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> .\/nginx.conf:\/etc\/nginx\/nginx.conf:ro\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> .\/certs:\/etc\/nginx\/certs:ro\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> .\/htpasswd:\/etc\/nginx\/.htpasswd:ro\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">depends_on<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> ollama\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">networks<\/span>:\n<\/span><span class=\"cbb-line\">      <span class=\"cbb-operator\">-<\/span> llm_backend\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">networks<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">llm_backend<\/span>:\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-attr\">driver<\/span>: bridge\n<\/span><span class=\"cbb-line\"><span class=\"cbb-attr\">volumes<\/span>:\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">ollama_data<\/span>:<\/span><\/code><\/pre><\/figure>\n<p>Before startup, <code>nginx.conf<\/code>, the password file and certificates must exist. The certificate must include <code>llm.example.internal<\/code> as a subject alternative name; the client needs the issuing CA certificate. <code>htpasswd -cB .\/htpasswd api_user<\/code> interactively creates a new bcrypt password file. The <code>-c<\/code> option overwrites an existing file, so subsequent account changes omit that option. File permissions must permit nginx to read the password file while restricting unrelated access; private keys require corresponding protection.<\/p>\n<p>NVIDIA acceleration additionally requires a compatible GPU, drivers, NVIDIA Container Toolkit and a GPU reservation in the Ollama service. CPU execution does not become GPU-accelerated merely through quantization. <code>depends_on<\/code> orders container startup but does not prove model readiness. A recreated backend may also require a proxy restart because this simple upstream configuration resolves the service address at nginx startup.<\/p>\n<h2>3. A proxy restricted to the required operation<\/h2>\n<p>This <code>nginx.conf<\/code> permits authenticated POST requests only at <code>\/api\/generate<\/code>. Other paths return 404; other methods on the permitted path are denied. Model administration stays outside the shared API. The proxy removes the Basic credentials before forwarding the request.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"nginx\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">nginx<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-nginx\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-keyword\">events<\/span> {<span class=\"cbb-keyword\"> worker_connections<\/span> <span class=\"cbb-number\">1024<\/span>; }\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">http<\/span> {\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">    upstream<\/span> ollama_backend {<span class=\"cbb-keyword\"> server<\/span> ollama:11434; }\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">    server<\/span> {\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        listen<\/span> <span class=\"cbb-number\">443<\/span> ssl;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        server_name<\/span> llm.example.internal;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        ssl_certificate<\/span> \/etc\/nginx\/certs\/server.crt;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        ssl_certificate_key<\/span> \/etc\/nginx\/certs\/server.key;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        ssl_protocols<\/span> TLSv1.2 TLSv1.3;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        client_max_body_size<\/span> <span class=\"cbb-number\">1m<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        location<\/span> <span class=\"cbb-operator\">=<\/span> \/api\/generate {\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            limit_except<\/span> POST {<span class=\"cbb-keyword\"> deny<\/span> all; }\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            auth_basic<\/span> <span class=\"cbb-string\">\"Local inference\"<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            auth_basic_user_file<\/span> \/etc\/nginx\/.htpasswd;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_pass<\/span> http:\/\/ollama_backend;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_http_version<\/span> <span class=\"cbb-number\">1.1<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_set_header<\/span> Host ollama:11434;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_set_header<\/span> Authorization <span class=\"cbb-string\">\"\"<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_set_header<\/span> Connection <span class=\"cbb-string\">\"\"<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_buffering<\/span> <span class=\"cbb-constant\">off<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_cache<\/span> <span class=\"cbb-constant\">off<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_connect_timeout<\/span> <span class=\"cbb-number\">5s<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_read_timeout<\/span> <span class=\"cbb-number\">600s<\/span>;\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">            proxy_send_timeout<\/span> <span class=\"cbb-number\">60s<\/span>;\n<\/span><span class=\"cbb-line\">        }\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">        location<\/span> \/ {<span class=\"cbb-keyword\"> return<\/span> <span class=\"cbb-number\">404<\/span>; }\n<\/span><span class=\"cbb-line\">    }\n<\/span><span class=\"cbb-line\">}<\/span><\/code><\/pre><\/figure>\n<p>Basic Auth authenticates a shared service account, not individual document permissions. Strong credentials, account revocation, request\/concurrency limits and log retention still need an operational design. The 1 MiB request limit is an example and may be too small for images. A compromised authorized application can still submit expensive requests or choose available models.<\/p>\n<h2>4. Connection verification with TLS checks<\/h2>\n<p>Model provisioning can use <code>docker compose exec ollama ollama pull llama3.1:8b<\/code> after the services have started. This is an example local model identifier, not a hardware recommendation. Pulling downloads a model; <code>ollama run<\/code> additionally starts an interactive session. The following curl request runs on the Docker host, prompts for the password and verifies the certificate against the supplied CA:<\/p>\n<figure style=\"--cbb-digits:1\" class=\"cbb cbb--wrap wp-block-code-beautifier-block-code\" data-lang=\"bash\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Shell<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-bash\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-function\">curl<\/span> <span class=\"cbb-attr\">--cacert<\/span> .\/certs\/ca.crt   <span class=\"cbb-attr\">--resolve<\/span> llm.example.internal:<span class=\"cbb-number\">8443<\/span>:127.0.0.1   <span class=\"cbb-attr\">--user<\/span> api_user   <span class=\"cbb-attr\">--header<\/span> <span class=\"cbb-string\">'Content-Type: application\/json'<\/span>   <span class=\"cbb-attr\">--data<\/span> <span class=\"cbb-string\">'{\"model\":\"llama3.1:8b\",\"prompt\":\"Return the word test.\",\"stream\":false}'<\/span>   https:\/\/llm.example.internal:<span class=\"cbb-number\">8443<\/span>\/api\/generate<\/span><\/code><\/pre><\/figure>\n<p>The test prompt contains no company information. A prompt asking for a policy summary does not make an absent policy available to the model. Verification should cover missing and incorrect credentials, a valid request, denied management paths, streaming, unavailable backend and actual port exposure. Syntax checks such as <code>docker compose config<\/code> and <code>nginx -t<\/code> are prerequisites, not evidence of an operational security boundary.<\/p>\n<div class=\"lw-faq\">\n<h2>Questions and answers<\/h2>\n<h3>Can Open WebUI or an OpenAI-compatible client use this unchanged?<\/h3>\n<p>No. The minimal gateway exposes only the native generation endpoint. A web UI needs additional reviewed endpoints and a network route to the proxy without direct backend access. A username and password embedded in a URL are not a portable integration method and can leak through configuration or logs. OpenAI-compatible clients normally send Bearer authorization; nginx Basic Auth expects a different scheme. Compatibility requires an explicit authentication adapter or a gateway supporting the chosen token scheme, plus the required <code>\/v1\/<\/code> paths. API compatibility covers only a subset of features.<\/p>\n<h3>Do 600 seconds limit the entire answer?<\/h3>\n<p>No. <code>proxy_read_timeout<\/code> limits the gap between upstream reads. Streaming chunks can extend the overall response beyond that duration; one generated token does not necessarily equal one network read. Without streaming, model loading and generation can delay the first response. The 5-second connection timeout is separate from response processing. Timeouts need measurement under the intended workload.<\/p>\n<h3>Does self-hosting guarantee data protection?<\/h3>\n<p>No. Access controls, legal basis, retention, backups, application logs and any external integrations remain relevant. A local backend is also not equivalent to the full ChatGPT product. The useful result is a defined inference service with a reviewable access path, not a guarantee of compliance, quality or complete isolation.<\/p>\n<\/div><div class=\"lw-quellen\"><h2>Sources<\/h2><ul><li><a href=\"https:\/\/github.com\/ollama\/ollama\/blob\/main\/README.md\" target=\"_blank\" rel=\"noopener noreferrer\">Ollama documentation<\/a><\/li><li><a href=\"https:\/\/docs.ollama.com\/faq\" target=\"_blank\" rel=\"noopener noreferrer\">Ollama FAQ<\/a><\/li><li><a href=\"https:\/\/docs.ollama.com\/api\/authentication\" target=\"_blank\" rel=\"noopener noreferrer\">Ollama authentication<\/a><\/li><li><a href=\"https:\/\/docs.ollama.com\/api\/openai-compatibility\" target=\"_blank\" rel=\"noopener noreferrer\">Ollama API compatibility<\/a><\/li><li><a href=\"https:\/\/docs.docker.com\/engine\/network\/port-publishing\/\" target=\"_blank\" rel=\"noopener noreferrer\">Docker port publishing<\/a><\/li><li><a href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_proxy_module.html\" target=\"_blank\" rel=\"noopener noreferrer\">nginx proxy module<\/a><\/li><li><a href=\"https:\/\/nginx.org\/en\/docs\/http\/ngx_http_auth_basic_module.html\" target=\"_blank\" rel=\"noopener noreferrer\">nginx Basic Auth<\/a><\/li><li><a href=\"https:\/\/curl.se\/docs\/sslcerts.html\" target=\"_blank\" rel=\"noopener noreferrer\">curl TLS verification<\/a><\/li><li><a href=\"https:\/\/www.edpb.europa.eu\/sme\/be-compliant\/secure-personal-data_en\" target=\"_blank\" rel=\"noopener noreferrer\">EDPB: Secure personal data<\/a><\/li><li><a href=\"https:\/\/httpd.apache.org\/docs\/2.4\/programs\/htpasswd.html\" target=\"_blank\" rel=\"noopener noreferrer\">Apache htpasswd<\/a><\/li><\/ul><\/div>","protected":false},"excerpt":{"rendered":"<p>A local Ollama service behind an nginx proxy with authentication and TLS: a CPU-based Compose example, restricted API access and checks of network exposure. GPU acceleration requires additional configuration.<\/p>\n","protected":false},"author":1,"featured_media":30124,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[92636],"tags":[91380,91113,91064,91404,91237,91099,91219,91115],"class_list":["post-489","post","type-post","status-publish","format-standard","hentry","category-tutorials-en-cloud-ai","tag-artificial-intelligence","tag-homelab","tag-linux","tag-llm","tag-self-hosting","tag-server-administration","tag-tutorial","tag-web-security"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Run Ollama behind Nginx: containers, GPU support, authentication, API access and checks of network and TLS boundaries.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Run Ollama behind Nginx: containers, GPU support, authentication, API access and checks of network and TLS boundaries.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-23T06:30:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-26T10:17:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-489-489.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"2 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy\",\"datePublished\":\"2026-09-23T06:30:00+00:00\",\"dateModified\":\"2026-10-26T10:17:35+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/\"},\"wordCount\":883,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-489-489.png\",\"keywords\":[\"Artificial Intelligence\",\"Homelab\",\"Linux\",\"LLM\",\"Self-Hosting\",\"Server Administration\",\"Tutorial\",\"Web Security\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/\",\"name\":\"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-489-489.png\",\"datePublished\":\"2026-09-23T06:30:00+00:00\",\"dateModified\":\"2026-10-26T10:17:35+00:00\",\"description\":\"Run Ollama behind Nginx: containers, GPU support, authentication, API access and checks of network and TLS boundaries.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-489-489.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/11\\\/flux-voll2-489-489.png\",\"width\":1200,\"height\":630,\"caption\":\"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/cloud-ai\\\/tutorials-en-cloud-ai\\\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy | Lukas Wojcik","description":"Run Ollama behind Nginx: containers, GPU support, authentication, API access and checks of network and TLS boundaries.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/","og_locale":"en_US","og_type":"article","og_title":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy | Lukas Wojcik","og_description":"Run Ollama behind Nginx: containers, GPU support, authentication, API access and checks of network and TLS boundaries.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-09-23T06:30:00+00:00","article_modified_time":"2026-10-26T10:17:35+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-489-489.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"2 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy","datePublished":"2026-09-23T06:30:00+00:00","dateModified":"2026-10-26T10:17:35+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/"},"wordCount":883,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-489-489.png","keywords":["Artificial Intelligence","Homelab","Linux","LLM","Self-Hosting","Server Administration","Tutorial","Web Security"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/","name":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-489-489.png","datePublished":"2026-09-23T06:30:00+00:00","dateModified":"2026-10-26T10:17:35+00:00","description":"Run Ollama behind Nginx: containers, GPU support, authentication, API access and checks of network and TLS boundaries.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-489-489.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/11\/flux-voll2-489-489.png","width":1200,"height":630,"caption":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/cloud-ai\/tutorials-en-cloud-ai\/self-hosted-large-language-model-llm-with-ollama-behind-an-auth-proxy\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Self-Hosted Large Language Model (LLM) with Ollama Behind an Auth Proxy"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/489","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=489"}],"version-history":[{"count":9,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/489\/revisions"}],"predecessor-version":[{"id":26463,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/489\/revisions\/26463"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/30124"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=489"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=489"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=489"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}