MaxKB
Overview
MaxKB is an open source platform, licensed under the GPL-3.0, for building question-answering agents on your own content using retrieval-augmented generation (RAG). You upload documents or crawl a website into a knowledge base, connect a language model, and publish an agent that answers from that content and shows which passages it used.
This SecureAnyCloud image runs MaxKB 2.10.8 LTS on Ubuntu 24.04 on Azure, with the whole stack on a single VM. Your agents are available in MaxKB's own chat page, embedded in your website, or through an OpenAI-compatible API.
What you get:
- MaxKB Community Edition, the web application and API for knowledge bases, agents, tools, chat logs and user management. It runs in a single container together with its PostgreSQL database (with the
pgvectorextension for vector search) and Redis. - A built-in embedding model that turns your documents into vectors on the VM, so knowledge bases work without any external service.
- Ollama serving a small local language model, Qwen2.5 1.5B Instruct, on the VM's CPU. It is already added to MaxKB, so you can build and test an agent as soon as you sign in, with no API key.
- nginx terminating HTTPS with a certificate generated for this VM.
- No default login. Upstream MaxKB creates its admin account with a published password. This image never lets that password exist. First boot gives the admin a password generated on your VM, verifies that the published default is refused, and writes the password to
/root/maxkb-credentials.txt(root-only). - Every secret unique to your VM. First boot generates the PostgreSQL and Redis passwords, MaxKB's secret keys and the TLS certificate. It also creates the database itself, so MaxKB's token signing keys are created in your own database too. Nothing is baked into the image, and the secrets reach MaxKB from a root-only file, never through a command line or the container's configuration.
- Patched beyond upstream. SecureAnyCloud rebuilt upstream's container image with the current security fixes: Python 3.11.17, every pending Debian and PostgreSQL package update (including OpenSSL, glibc and pgvector 0.8.7) and patched versions of the Python packages a vulnerability scan flagged. The image is flattened to a single layer without the TLS key pair that upstream's own image build left in every copy, so no key shared with other copies of the upstream image ships.
- HTTPS from the first boot. nginx serves MaxKB on port 443 with a certificate generated on your VM's first boot, and with HSTS. Port 80 redirects to HTTPS on the VM's own address, never to a host name a client sends, and requests for host names the VM does not serve are dropped. MaxKB listens on
127.0.0.1:8080. PostgreSQL, Redis and the embedding model listen on the container's own loopback. Ollama listens on a private Docker bridge address that only the VM itself and the MaxKB container can reach. - Closed until first boot, and fail-closed. MaxKB and Ollama cannot start before first boot has written their secrets. MaxKB refuses to start if the secrets are missing, too short or an upstream default. nginx starts only after the admin password check has passed. If first boot fails, it removes its markers and stops everything.
- Custom tools in a sandbox. Python tools you write in MaxKB run as a separate
sandboxuser. On top of MaxKB's own connection filter, kernel firewall rules inside the container refuse that user's connections to PostgreSQL, Redis, the embedding server, MaxKB itself, Ollama, the Azure metadata service, the WireServer and the VM's own addresses. PostgreSQL's socket directory is closed to that user, and it cannot read the stack's passwords. - No Azure metadata access. Every container, MaxKB's services, nginx, Docker, containerd and Ollama are blocked from the Azure Instance Metadata Service (
169.254.169.254) and the Azure WireServer (168.63.129.16, whose DNS keeps working). A link in a web knowledge base, a tool or a model setting therefore cannot read this VM's identity or managed identity tokens. - A fully patched Ubuntu 24.04 LTS base at build time, with unattended security upgrades switched on.
- 24/7 SecureAnyCloud support.
Components, versions and licences:
MaxKB Community Edition: 2.10.8 LTS (v2.10.8-lts), GPL-3.0.
PostgreSQL + pgvector (inside the MaxKB container): 17.11 + 0.8.7, PostgreSQL Licence.
Redis (inside the MaxKB container): 8.0.6, AGPL-3.0.
Ollama (CPU): 0.40.11, MIT.
Qwen2.5 1.5B Instruct (qwen2.5:1.5b, Q4_K_M): Ollama manifest f2b0a490, Apache 2.0.
Embedding model text2vec-base-chinese (bundled in MaxKB): as shipped in 2.10.8 LTS, Apache 2.0.
Docker Engine: 29.9.2, Apache 2.0.
About the local model. Qwen2.5 1.5B is small enough to run on a CPU, which is what makes this image work out of the box. It is still a small model. On a Standard_B4ms it answers a typical knowledge base question in roughly 5 to 30 seconds, and the first question after a quiet period also loads the model. It handles one question at a time, and it can misread negations or questions that need several steps of reasoning.
The local model is a good way to build, test and demonstrate agents. For production traffic, connect a hosted model such as Azure OpenAI or OpenAI (Step 10). MaxKB lets you choose the model per agent.
This image contains the Community Edition, which MaxKB itself limits to 50 knowledge bases, 5 agents and 2 user accounts (the admin plus one more). The Upgrade button in the MaxKB header points to FIT2CLOUD's commercial Professional Edition. That edition needs a licence from FIT2CLOUD and is not included in this image. Every feature this guide describes is part of the open source Community Edition.
MaxKB is developed by FIT2CLOUD and the 1Panel community under the GPL-3.0. Ollama is developed by Ollama Inc. under the MIT licence, and Qwen2.5 by the Qwen team at Alibaba Cloud under the Apache 2.0 licence. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by FIT2CLOUD, the MaxKB or 1Panel projects, Ollama or Alibaba Cloud. The names are used here solely to identify the software this image contains.
Prerequisites
- An Azure subscription with permission to create VMs.
- A
Standard_B4msVM (4 vCPU, 16 GiB) or larger is recommended. MaxKB with its database uses about 2 GiB, and the local model uses about 1.5 GiB while loaded. Extra CPU makes local answers and document processing faster. - Inbound TCP
443(and80for the redirect) open only to the networks you connect from, plus22for SSH administration. Never open 8080, 11434, 5432 or 6379: MaxKB, Ollama and the database are not on the network. - An SSH key pair (or a password) for administrative access.
- Optional: an API key or endpoint for a hosted model (Azure OpenAI, OpenAI, Anthropic, Google Gemini, DeepSeek and others), if you want faster, stronger answers than the local model.
Deploy from the Azure Portal
- In the Azure Portal, search the Marketplace for MaxKB, select the SecureAnyCloud offer, then select Create.
- Choose your subscription, resource group and region.
- Set the VM size to Standard_B4ms or larger.
- Under Administrator account, select SSH public key (recommended) and supply your own key.
- Under Inbound port rules, allow HTTPS (443), HTTP (80) and SSH (22). Then restrict all three to your own address ranges on the networking blade.
- Select Review + create, then Create.
Deploy from the Azure CLI
Accept the Marketplace terms, create the VM, then open HTTPS and the HTTP redirect to your own network only. Replace the example range 203.0.113.0/24 with your own.
az vm image terms accept --urn sac1647283583153:maxkb-ubuntu-24-04:default:latest
az vm create \
--resource-group my-resource-group \
--name my-maxkb \
--image sac1647283583153:maxkb-ubuntu-24-04:default:latest \
--size Standard_B4ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
# Open HTTPS (and the HTTP redirect) to YOUR network only. MY_CIDR="203.0.113.0/24"
# replace with your own range
az network nsg rule create \
--resource-group my-resource-group \
--nsg-name my-maxkbNSG \
--name allow-https-from-office --priority 1010 \
--source-address-prefixes "${MY_CIDR}" \
--destination-port-ranges 80 443 --protocol Tcp --access AllowConnect to your VM
Connect to the VM over SSH as the administrator user you set at deployment.
ssh azureuser@<vm-ip>Confirm the services are running
Check that every service is active and that first boot has finished. First boot takes two to three minutes. It generates this VM's secrets and certificate, creates MaxKB's database, starts Ollama and MaxKB, sets the admin password, registers the local model and opens nginx. It ends with a sign-in check.
systemctl is-active docker maxkb-egress-guard ollama maxkb nginx maxkb-firstboot
sudo test -f /var/lib/sac/data/maxkb-firstboot.done && echo FIRSTBOOT_DONEactive active active active active active FIRSTBOOT_DONEConfirm the listening ports. Only SSH (22) and nginx (80, 443) listen on public addresses. MaxKB listens on 127.0.0.1:8080, and Ollama listens on the private Docker bridge address 172.30.250.1:11434.
sudo ss -lntH | awk '{print $4}' | grep -vE '^127\.0\.0\.5[34]' | grep -vE '^127\.0\.0\.1:[0-9]{5}$' | sort -u0.0.0.0:22 0.0.0.0:443 0.0.0.0:80 127.0.0.1:8080 172.30.250.1:11434 [::]:22 [::]:443 [::]:80MaxKB runs as a single container from the SecureAnyCloud-patched image:
sudo docker ps --format '{{.Names}} {{.Image}} {{.Ports}}'maxkb sac/maxkb:v2.10.8-lts-sac 5432/tcp, 6379/tcp, 127.0.0.1:8080->8080/tcpPorts 5432/tcp and 6379/tcp belong to PostgreSQL and Redis inside the container. They are not published to the VM or the network.
Get your URL and sign in
Read the console URL, the user name and the local model's endpoint from the credentials file:
sudo grep -E '^(MAXKB_URL|MAXKB_USERNAME|OLLAMA_URL)=' /root/maxkb-credentials.txtMAXKB_URL=https://<vm-ip>/admin/ MAXKB_USERNAME=admin OLLAMA_URL=http://172.30.250.1:11434The password is in the same root-only file. Display the whole file when you need it:
sudo cat /root/maxkb-credentials.txtMAXKB_URLis the address of the MaxKB console. It uses this VM's public IP address from the Azure Instance Metadata Service, or its private address if it has no public one. The certificate also names the private address. To use your own DNS name, see Step 13.MAXKB_USERNAMEandMAXKB_PASSWORDsign you in as the administrator.MAXKB_NEW_USER_DEFAULT_PASSWORDis the initial password MaxKB fills in when you create the second user. It cannot sign in as the admin.
Open MAXKB_URL in a browser. The certificate is self-signed and generated for this VM, so your browser shows a warning the first time. Continue past it, or install your own certificate (Step 13).
Sign in as admin with the password from the file. Then change it under the avatar menu, Change Password. The new password must be 6 to 20 characters with an upper-case letter, a lower-case letter, a digit and a special character.
After one failed sign-in, MaxKB asks for a CAPTCHA. After five failures it locks the account for ten minutes. nginx also limits each client address to 10 sign-in attempts a minute.
Confirm that nothing is open without signing in
Request the admin, model, knowledge and profile APIs without signing in. Each one should answer HTTP 401.
C=/etc/ssl/maxkb/maxkb.crt; U=https://127.0.0.1 for p in /admin/api/user/profile /admin/api/workspace/default/application /admin/api/workspace/default/knowledge /admin/api/workspace/default/model; do echo "GET $p (not signed in) -> HTTP $(curl -s --cacert $C -o /dev/null -w '%{http_code}' $U$p)"; done curl -s --cacert $C $U/admin/api/profile | jq -c '.data | {version, edition}'GET /admin/api/user/profile (not signed in) -> HTTP 401 GET /admin/api/workspace/default/application (not signed in) -> HTTP 401 GET /admin/api/workspace/default/knowledge (not signed in) -> HTTP 401 GET /admin/api/workspace/default/model (not signed in) -> HTTP 401 {"version":"v2.10.8-lts (build at 2026-10-22T10:35, commit: 792a525)","edition":"CE"}Then confirm that MaxKB's published default password is refused:
U=https://127.0.0.1; C=/etc/ssl/maxkb/maxkb.crt printf '{"username":"admin","password":"MaxKB@123.."}' | curl -s --cacert $C -H 'Content-Type: application/json' --data @- $U/admin/api/user/login | jq -c '{code, message}'{"code":1005,"message":"Login failed 5 times, account will be locked, you have 4 more chances !"}That attempt counts as a failed sign-in. The next time you sign in as admin, MaxKB asks for a CAPTCHA, or you can wait ten minutes. From another machine, use MAXKB_URL instead of https://127.0.0.1, and add -k because the certificate is self-signed.
The bundled local model
Open Model in the top menu. Two models are ready:
- Qwen2.5 1.5B (local, CPU): the local language model served by Ollama on this VM.
- maxkb-embedding: MaxKB's built-in embedding model, which knowledge bases use to index your documents.
You can also talk to the local model directly from the VM. Ollama listens only on the private Docker bridge address.
curl -s http://172.30.250.1:11434/api/tags | jq -r '.models[] | "\(.name) \(.details.parameter_size) \(.details.quantization_level)"'
curl -s http://172.30.250.1:11434/api/chat \
-d '{"model":"qwen2.5:1.5b","stream":false,"messages":[{"role":"user","content":"In one sentence, what is a knowledge base?"}]}' \
| jq -r .message.contentExample output. The model writes the second line, so your wording will differ.
qwen2.5:1.5b 1.5B Q4_K_M A knowledge base is a repository of information, often in the form of knowledge articles or data, used to store and manage knowledge and expertise.Build a knowledge base
- Open Knowledge, select Create, then General Knowledge.
- Give the knowledge base a name and keep maxkb-embedding as the embedding model.
- Select Upload Document and add your files. MaxKB accepts PDF, Word, Markdown, text, HTML, Excel and CSV files, among others. It splits each document into segments and indexes them on the VM. The File Status column shows Successful when a document is ready.
- To crawl a website instead of uploading files, use Web Knowledge. It can sync the site again later.
- Open Retrieval Testing in the knowledge base's menu to see which segments a question would retrieve. This lets you check your content before you build an agent. For English content, the hybrid search mode usually ranks best with the built-in embedding model, which was trained mainly on Chinese text. You can add another embedding model under Model if your knowledge base needs it.
- Indexing runs on the VM's CPU. It takes a few seconds for a small document and minutes for a large PDF.
Create an agent, publish it and use its API
- Open Agent, select Create, then Simple Agent. Give the agent a name and a description.
- Under AI Model, choose Qwen2.5 1.5B (local, CPU), or any hosted model you have added (Step 10).
- Next to Related Knowledge, select + and add your knowledge base.
- Under Prologue, write the greeting your users will see, with suggested questions as list items.
- Select Save, then ask a question in Debug Preview on the right. The answer shows the Knowledge Source it used.
Select Publish to make the agent available. Its Overview page then shows three things:
- Public URL: a chat page anyone with the link can use without signing in, with an On switch.
- Get Embed Code: a snippet for your own website.
- API Access Credentials: a base URL and API key for the agent's OpenAI-compatible chat API.
Call the chat API like this:
MAXKB_BASE="https://<vm-ip>/chat/api/<agent-id>" curl -sk "$MAXKB_BASE/chat/completions" -H "Authorization: Bearer <agent-api-key>" -H 'Content-Type: application/json' \
-d '{"messages":[{"role":"user","content":"What are your support hours?"}],"stream":false}' | jq -r '.choices[0].message.content'Public chat is per agent. A new VM has no agents, so it has no public chat page at all. An agent's public page answers only after you publish the agent, and you can switch it off at any time.
Anyone with the link can ask questions, and every question uses your model. Share the link as you would share an API key, and keep the VM's network rule limited to the people who should reach it.
Hosted models and outbound access
MaxKB's container can reach the public internet out of the box, so you can add a hosted model or a web knowledge base straight away. Addresses in your virtual network and other private ranges are closed until you allow one. The Azure metadata service and WireServer are always closed. Check the current policy:
sudo maxkb-egress status | head -3MODE=open ALLOW=none Chain MAXKB-EGRESS (1 references)To add a hosted model, open Model and select Add Model. Choose the provider (Azure OpenAI, OpenAI, Anthropic, Google Gemini, DeepSeek, an OpenAI-compatible service, or another Ollama server) and enter its endpoint and key. Then pick the model under AI Model in your agent.
MaxKB checks the model by calling it when you save. Keys you enter are stored encrypted in MaxKB's database on this VM. Your provider bills you for the tokens your agents use.
You can also change what the container may reach:
- A model server in your virtual network (Ollama, vLLM, LM Studio, LiteLLM): allow just that address and port, and allow this VM in that server's network rules. For example:
sudo maxkb-egress allow 10.0.1.20:11434
- Keep MaxKB entirely on the VM (the bundled local model only): close the internet too. The bundled model and DNS keep working. Run:
sudo maxkb-egress close
sudo maxkb-egress open returns to the shipped default, and sudo maxkb-egress deny <address> removes an allowed address. The policy is kept in /etc/maxkb/egress.conf and applied by the VM's firewall, not by anything inside the container.
Run the built-in check
The image ships an end-to-end check that you can run at any time. First boot runs it too. The check reads the credentials file itself and talks to MaxKB over HTTPS through nginx, with the VM's certificate pinned. It verifies that:
- Port 80 redirects, an unknown host name is dropped, and the console is served.
- Every admin, model, knowledge, tool and user API, and the OpenAI-compatible chat API, refuse an anonymous request.
- A made-up public chat token, the published default password, a wrong password and forged session tokens are all refused.
- This VM's password signs in with a
SecureandHttpOnlycookie. - The bundled model is registered.
Run it with:
sudo maxkb-verify.shport 80 -> 301 https://<vm-ip>/ ; an unknown Host is dropped on 80 and 443 ; certificate verifies for <vm-ip> ; UI served anonymous: 6 admin/model/knowledge/tool/user APIs 401, OpenAI-compatible chat 401, made-up public token refused (agents/tokens/users: 0 0 1) sign-in: MaxKB@123.. refused, wrong password refused, this VM's password -> token -> 200 (Secure + HttpOnly cookie); bundled qwen2.5:1.5b registered; forged tokens 401 (MaxKB v2.10.8-lts CE) MAXKB_ROUNDTRIP_OKSecurity checks
The files that hold secrets are root-only, and the database and Redis use this VM's passwords. List their permissions and the variable names in the environment file:
sudo stat -c '%a %U:%G %n' /etc/maxkb /etc/maxkb/maxkb.env /root/maxkb-credentials.txt /etc/ssl/maxkb/maxkb.key /var/lib/maxkb/conf/redis.conf
sudo grep -oE '^[A-Z_]+=' /etc/maxkb/maxkb.env700 root:root /etc/maxkb 600 root:root /etc/maxkb/maxkb.env 600 root:root /root/maxkb-credentials.txt 600 root:root /etc/ssl/maxkb/maxkb.key 600 root:root /var/lib/maxkb/conf/redis.conf POSTGRES_PASSWORD= <set-at-first-boot>= MAXKB_DB_PASSWORD= <set-at-first-boot>= MAXKB_REDIS_PASSWORD= <set-at-first-boot>= MAXKB_HMAC_SIGNED_SERIALIZER_SECRET_KEY= MAXKB_DEFAULT_PASSWORD= <set-at-first-boot>= MAXKB_TIME_ZONE= TZ= MAXKB_SANDBOX_PYTHON_BANNED_HOSTS=MaxKB reads these secrets from that file, which is mounted read-only into its container. The secrets are therefore not part of the container's configuration:
sudo bash -c 'grep -E "^(POSTGRES_PASSWORD|REDIS_PASSWORD|MAXKB_SECRET_KEY)=" /etc/maxkb/maxkb.env | cut -d= -f2- > /run/s; echo "secret values in docker inspect: $(docker inspect maxkb | grep -cF -f /run/s)"; rm -f /run/s'secret values in docker inspect: 0PostgreSQL accepts only scram-sha-256 password logins, over the container's own loopback.
sudo grep -vE '^\s*(#|$)' /var/lib/maxkb/data/postgresql/pgdata/pg_hba.conflocal all all scram-sha-256 host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 local replication all scram-sha-256 host replication all 127.0.0.1/32 scram-sha-256 host replication all ::1/128 scram-sha-256 host all all all scram-sha-256These commands show the VM's firewall rules for the containers, and what the Azure metadata service and WireServer look like from inside the MaxKB container.
sudo iptables -S DOCKER-USER | sed -n 2,6p
sudo docker exec maxkb /opt/py3/bin/python -c ' import urllib.request for name, url in [("Azure IMDS ", "http://169.254.169.254/metadata/instance?api-version=2021-02-01"), ("Azure WireServer", "http://168.63.129.16/?comp=versions"), ("Internet ", "https://www.example.com/")]: try: print(name, urllib.request.urlopen(urllib.request.Request(url, headers={"Metadata": "true"}), timeout=6).status) except Exception: print(name, "blocked") '-A DOCKER-USER -i br-maxkb -j MAXKB-EGRESS -A DOCKER-USER -d 168.63.129.16/32 -p udp -m udp --dport 53 -j RETURN -A DOCKER-USER -d 168.63.129.16/32 -p tcp -m tcp --dport 53 -j RETURN -A DOCKER-USER -d 168.63.129.16/32 -j DROP -A DOCKER-USER -d 169.254.0.0/16 -j DROP Azure IMDS blocked Azure WireServer blocked Internet 200The MaxKB service, nginx, containerd and Ollama are denied the metadata service and WireServer too. The Docker daemon is denied the metadata service and reaches the WireServer only for DNS.
systemctl show maxkb nginx containerd docker ollama -p Id -p IPAddressDeny | paste - - -IPAddressDeny=169.254.169.254/32 168.63.129.16/32 Id=maxkb.service IPAddressDeny=169.254.169.254/32 168.63.129.16/32 Id=nginx.service IPAddressDeny=169.254.169.254/32 168.63.129.16/32 Id=containerd.service IPAddressDeny=169.254.169.254/32 Id=docker.service IPAddressDeny=169.254.0.0/16 168.63.129.16/32 Id=ollama.serviceCustom Python tools run as the container's sandbox user (uid 1000). The kernel refuses that user's connections to the stack.
sudo nsenter -t "$(sudo docker inspect -f '{{.State.Pid}}' maxkb)" -n iptables -S OUTPUT | grep SAC-SANDBOX
sudo nsenter -t "$(sudo docker inspect -f '{{.State.Pid}}' maxkb)" -n iptables -S SAC-SANDBOX | grep -c REJECT-A OUTPUT -m owner --uid-owner 1000 -j SAC-SANDBOX 14nginx passes MaxKB a fixed host name and the real client address from the connection, never values a client sends. It also marks every cookie Secure and HttpOnly.
grep -E 'proxy_set_header (Host|X-Forwarded-For|X-Real-IP|Forwarded)|proxy_cookie_flags' /etc/nginx/maxkb-proxy.confproxy_set_header Host $maxkb_host; proxy_set_header Forwarded ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_cookie_flags ~ secure httponly;Finally, confirm that no password or key reached a log, the journal, the container's log or configuration, shell history, backups or /etc (other than the secrets file):
sudo maxkb-secret-leak-check.shLEAKCHECK_OK no password or key in the journal, auth.log, syslog, cloud-init, nginx, the container log or configuration, MaxKB's logs, shell history, MOTD, /var/backups, /etc (only maxkb.env), /usr/local or /tmpYour own DNS name and certificate
Point a DNS record at the VM's public IP, then set the name that MaxKB is served under. The command creates a new self-signed certificate for the name, updates nginx's host rule and the URL in /root/maxkb-credentials.txt, and reloads nginx. The name is kept across reboots.
sudo maxkb-set-hostname <your-domain>Without a configured name, the VM re-reads its address from the Azure Instance Metadata Service at every boot. A deallocate and start that changes the public IP address therefore keeps MaxKB reachable.
To use a certificate from your own certificate authority (for example Let's Encrypt) instead, copy it over /etc/ssl/maxkb/maxkb.crt and maxkb.key (key mode 0600), then run sudo systemctl reload nginx. Running maxkb-set-hostname again replaces your certificate with a self-signed one.
Day-2 operations
Reset the admin password. If the admin password is lost, set a new random one. The command writes it to /root/maxkb-credentials.txt:
sudo maxkb-reset-admin-passwordRestart. sudo systemctl restart maxkb restarts the MaxKB container. The console answers again after about a minute. sudo systemctl restart ollama restarts the local model server.
Back up. Everything MaxKB stores (the database, uploaded files and logs) is under /var/lib/maxkb, and its secrets are in /etc/maxkb. Snapshot the VM's OS disk in Azure, or stop MaxKB first for a consistent copy:
sudo systemctl stop maxkb
sudo tar -C / -czf /root/maxkb-backup-$(date +%F).tar.gz var/lib/maxkb etc/maxkb
sudo systemctl start maxkbThe archive contains your secrets, so keep it as private as the VM itself.
Add more local models. Choose a model whose licence suits you and pull it into the local Ollama. Then add it in MaxKB under Model > Add Model > Ollama with the API URL http://172.30.250.1:11434:
OLLAMA_HOST=172.30.250.1:11434 ollama pull qwen2.5:3bLarger models answer better but more slowly on a CPU, and they need more memory. Allow roughly the model's download size again in free RAM.
Updates. Ubuntu security updates install automatically. MaxKB runs from the SecureAnyCloud-patched image sac/maxkb:v2.10.8-lts-sac, and the MaxKB unit checks it against the image this VM image was built with. SecureAnyCloud publishes a new image version for new MaxKB releases and security fixes.
Server components
Print the component manifest to see the exact versions, digests and sources shipped in this image.
cat /usr/share/maxkb-appliance/VERSIONSMaxKB v2.10.8-lts Community Edition (github.com/1Panel-dev/MaxKB, GPL-3.0), commit 792a525c5a78e42bf04b91c251f747a0bc3e8517. Upstream image: docker.io/1panel/maxkb@sha256:27ac6c21323e5018078f7a1c4c2d82dc9ab48725b65165cb54fca5e540f66216 (linux/amd64), built by upstream's public GitHub Actions workflow from that commit. Shipped image: sac/maxkb:v2.10.8-lts-sac = sha256:a1101c898f8c0f340698b5df15a1c3c82d594fb156374aaf802442238858f9db, upstream plus the sac same-line patch layer (CPython 3.11.17 from docker.io/library/python@sha256:b95327ce1439e687237841b0210677aeadd62d55a060a5f6bcb9c15bf6251dd3, Debian trixie/security/PGDG updates, curl and vim removed, djangorestframework 3.18.3, pypdf 6.21.2, pip 26.2.2, setuptools 84.2.1), flattened to one layer. Ollama v0.40.11 (MIT, https://github.com/ollama/ollama/releases/download/v0.40.11/ollama-linux-amd64.tar.zst, sha256 7bedab90dd122661be78798e9f0edf37fccf0cccf2699d2c58ea1a3afdc04b6d, CPU backends only) serving qwen2.5:1.5b (Qwen2.5 1.5B Instruct Q4_K_M, Apache-2.0, manifest sha256 f2b0a490f661d58f20c4b98e5797ecf55e6e96293a88b71e96e7cc389f658f7e). Docker Engine 5:29.9.2-1~ubuntu.24.04~noble, containerd.io 2.4.2-3~ubuntu.24.04~noble, nginx 1.24.0-2ubuntu7.18.Known open upstream items. After SecureAnyCloud's patches, a vulnerability scan of the container still lists items that have no fixed release yet:
- diskcache 5.6.3 (unsafe data in its cache directory). The cache directory inside the container is writable by root only.
- Debian packages that Debian has not fixed for this release or marks as minor, among them glibc, util-linux, ncurses, perl, and the Kerberos and SASL client libraries (PostgreSQL uses neither).
- libxml2 CVE-2026-6653, reachable only through PostgreSQL's XML functions, which MaxKB does not use. MaxKB's tool sandbox has no database access: the image's build tests that a Python tool cannot connect to PostgreSQL or Redis over TCP or PostgreSQL's socket, and cannot read their passwords. SecureAnyCloud re-checks this at each MaxKB release.
- Redis's cluster bus. Cluster mode is off, and Redis listens on the container's loopback.
SecureAnyCloud publishes a new image version when MaxKB or Debian release fixes.
Troubleshooting
- The browser warns about the certificate. The certificate is self-signed. Continue once, or install your own certificate (Step 13). For
curl, pass--cacert /etc/ssl/maxkb/maxkb.crton the VM or-kelsewhere. - The connection is closed without a response. The request used a host name the VM does not serve, and nginx drops unknown names. Use
MAXKB_URLor the VM's IP address, or set your own name withmaxkb-set-hostname. - Adding a model in your virtual network fails with a connection error. Private ranges are closed (Step 10). Allow the server with
sudo maxkb-egress allow <ip>:<port>, then save the model again. - 502 Bad Gateway. MaxKB is still starting. After a reboot or restart it takes about a minute. Wait and reload.
- Sign-in asks for a CAPTCHA. A previous attempt failed. Enter the CAPTCHA, or wait ten minutes. HTTP 429 means too many attempts from your address. Wait a minute.
- Answers are slow. The local model runs on the CPU. Use a larger VM, keep questions and knowledge base segments short, or connect a hosted model (Step 10).
- MaxKB does not start.
journalctl -u maxkbshows what the preflight check refused. - First boot.
journalctl -u maxkb-firstbootshows what first boot did, and it never prints a password. If first boot failed, it closed everything. Fix the cause and runsudo systemctl restart maxkb-firstboot.
Security recommendations
- Limit network access. Restrict the network security group to your own networks. Keep outbound access only as wide as your models need:
maxkb-egress closeif you use only the bundled model,maxkb-egress allowfor a model server in your virtual network. - Choose your model provider with care. MaxKB sends your questions and the retrieved document text to the model you configure. Pick a provider whose data handling suits your documents. The bundled local model keeps everything on the VM.
- Protect published agents. Treat published agent links and agent API keys like passwords, and switch off public access for agents that do not need it.
- Review custom tools. Review custom Python tools before you enable them. They run as the sandbox user described in Step 12.
Support
SecureAnyCloud provides 24/7 support for this image by email and live chat at sales@secureanycloud.com. Include your VM's region and the output of sudo journalctl -u maxkb-firstboot --no-pager | tail -n 50.
MaxKB is licensed under the GNU General Public License v3 (/usr/share/doc/sac/maxkb/LICENSE). The source code is at https://github.com/1Panel-dev/MaxKB. This image contains the Community Edition only.
Deploy on Azure
Launch MaxKB on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com