Do
Artificial Intelligence (AI) Azure

DeepWiki-Open on Ubuntu 24.04 on Azure User Guide

| Product: DeepWiki-Open on Ubuntu 24.04 LTS on Azure

Overview

DeepWiki-Open turns a code repository into documentation you can actually read. You give it a GitHub, GitLab or Bitbucket URL; it clones the repository, indexes every source file for retrieval, and asks an AI model to write a structured wiki about the codebase — an architecture overview, per component pages, Mermaid diagrams of how the pieces fit together, and an Ask panel that answers questions about the code with reference to the real files.

The distinction from a README matters: the wiki is generated from the code itself rather than from whatever the maintainers remembered to write down, so it is useful precisely on the repositories that are least documented — an inherited service, a vendor's open source dependency, or your own codebase from three years ago.

DeepWiki calls an AI provider, it does not host a model. That is what makes it cheap to run: no GPU, one small VM, and you bring your own provider key so you keep full control of which model you use and what it costs.

This cloudimg image runs DeepWiki-Open installed from upstream source pinned to an exact commit, built into a production Next.js server and a FastAPI backend, both bound to the VM's loopback interface behind nginx on port 80. Because DeepWiki upstream has no sign in of any kind, cloudimg locks the whole instance behind a credential that every VM generates for itself on first boot, so an instance is never left open to strangers. Backed by 24/7 cloudimg support.

What is included:

  • DeepWiki-Open (AsyncFuncAI/deepwiki-open, MIT), installed from upstream source pinned to commit a562c789e72f211333042b360e42d479e8ed8791 so the shipped version never drifts
  • The Python backend and the compiled Next.js frontend as native systemd services — no containers, so nothing can be resurrected by a container daemon before the security gate exists
  • nginx on :80 enforcing HTTP Basic authentication against a per-VM credential, including on the WebSocket that live wiki generation streams over
  • A fail closed authentication gate: nginx refuses to start if the credential file is ever missing
  • An unauthenticated /healthz endpoint for load balancer and uptime checks
  • No AI provider key of any kind baked into the image — you add your own after launch
  • A background task that strips access tokens out of cloned private repositories every minute
  • nginx.service, deepwiki-api.service, deepwiki-web.service and deepwiki-firstboot.service as systemd units, enabled and active
  • 24/7 cloudimg support

Service status and the listening sockets on a running DeepWiki-Open VM

How this image is secured

DeepWiki-Open upstream is designed for local, single user use. It ships no authentication worth the name: the only thing in the codebase resembling a gate is DEEPWIKI_AUTH_MODE, which is off by default, is a single shared code rather than an account system, and guards exactly one route out of twelve. Deployed as upstream ships it, a VM on a public IP with a working provider key would let anyone who finds it spend your AI credits — and because generating one wiki embeds an entire repository and then runs many long model calls, that is an expensive door to leave open. This image closes it four ways:

  1. nginx requires a credential on every path except the static /healthz probe — including /ws/chat, the WebSocket that wiki generation actually runs over. The username is randomised per VM and the password is 24 random characters, both generated on this VM at first boot and written to a root only file. There is no default, shared or documented credential at any point.
  2. Port 80 stays shut until the credential exists. nginx.service carries a condition on a marker file that first boot creates only after it has minted the credential and confirmed that an unauthenticated request is refused. A customer VM cannot serve a single request before it is locked down.
  3. The gate is fail closed, not fail open. nginx.service also runs a pre start assertion that re-checks the authentication directives and the credential file. If either is ever missing, nginx will not start at all rather than serving openly. Step 7 below demonstrates this on your own VM.
  4. The application does not start until it is configured. Both deepwiki-api.service and deepwiki-web.service carry a condition on the per-VM environment file, which is absent from the image, so the enabled units are a no-op until first boot writes it.

Anonymous requests, the anonymous wiki generator socket and default credentials all refused with 401 while the per-VM credential is accepted with 200

Prerequisites

  • An Azure subscription with permission to create virtual machines
  • An SSH key pair for the azureuser account
  • A network security group allowing inbound 22 (SSH) and 80 (HTTP) from your address
  • An API key from an AI provider — OpenAI is the quickest start because one key covers both wiki generation and the embeddings used for retrieval. Google Gemini, OpenRouter, Azure OpenAI and Amazon Bedrock are also supported, as is a fully local Ollama server if you prefer to keep everything in your own network.
  • Recommended size Standard_B2ms (2 vCPU / 8 GiB). The frontend, the Python backend and the in-process FAISS retrieval index all live on this VM, and indexing a large repository is memory hungry.

Step 1 — Launch the VM

From the Azure portal, choose the cloudimg DeepWiki-Open on Ubuntu 24.04 LTS image, pick Standard_B2ms, and allow inbound 22 and 80.

From the Azure CLI:

az vm create \
  --resource-group my-resource-group \
  --name deepwiki-01 \
  --image cloudimg:deepwiki-open-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

az vm open-port --resource-group my-resource-group --name deepwiki-01 --port 80 --priority 900

First boot takes about a minute. During that minute deepwiki-firstboot.service generates this VM's own sign in credential, writes the environment file, starts both application services and only then opens port 80.

Step 2 — Retrieve this VM's sign in credential

SSH in and read the credentials file. It is 0600 root:root, so it needs sudo:

ssh azureuser@<vm-public-ip>

Then, on the VM:

sudo cat /root/deepwiki-credentials.txt

Expected output (your values will differ — every VM generates its own):

# DeepWiki-Open - generated on first boot by deepwiki-firstboot.service
# These values are unique to this VM. Store them somewhere safe.

deepwiki.url=http://<vm-ip>/
deepwiki.web.username=cloudimg-a1b2c3
deepwiki.web.password=************************

The per-VM credentials file and the commented provider key lines that ship with no key set

Confirm the services are up and that only port 80 is exposed:

systemctl is-active nginx deepwiki-api deepwiki-web
active
active
active
ss -tln | awk '{print $4}' | grep -E ':(80|3000|8001)$' | sort -u
0.0.0.0:80
127.0.0.1:3000
127.0.0.1:8001
[::]:80

The frontend on 3000 and the backend on 8001 are bound to the loopback interface only. Nothing reaches them except through the authenticated nginx proxy on port 80.

Step 3 — Confirm the instance is not open to strangers

Before you add a provider key, prove the gate is doing its job. An anonymous request is refused:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/
401

So is an anonymous attempt to open the wiki generation socket — this is the one that matters, because that socket is where your AI credits are spent:

curl -s -o /dev/null -w '%{http_code}\n' \
  -H 'Connection: Upgrade' -H 'Upgrade: websocket' \
  -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' \
  http://127.0.0.1/ws/chat
401

Common default credentials are refused:

curl -s -o /dev/null -w '%{http_code}\n' -u admin:admin http://127.0.0.1/
401

The health probe stays open so load balancers work without a credential:

curl -s http://127.0.0.1/healthz
ok

Step 4 — Add your AI provider key

DeepWiki needs two things from a provider: a model to write the wiki, and an embedding model to index the repository so the wiki and the Ask panel can cite real files. The image ships neither — every provider key line in the environment file is commented out.

sudo nano /etc/deepwiki/deepwiki.env

Uncomment OPENAI_API_KEY and paste your own key. One OpenAI key covers both generation and embeddings, which is why it is the quickest start:

OPENAI_API_KEY=sk-your-own-key-here

To use Google Gemini for generation instead, set GOOGLE_API_KEY and change DEEPWIKI_EMBEDDER_TYPE to google. To use OpenRouter, set OPENROUTER_API_KEY and keep an OpenAI or Google key for embeddings. Azure OpenAI and Amazon Bedrock are configured in the same file. If you would rather no data leaves your network at all, run Ollama and set DEEPWIKI_EMBEDDER_TYPE=ollama with OLLAMA_HOST.

Restart both services so they pick the key up:

sudo systemctl restart deepwiki-api deepwiki-web
systemctl is-active deepwiki-api deepwiki-web
active
active

The key is read from a 0600 file owned by root and is never written anywhere else.

Step 5 — Sign in and generate your first wiki

Open http://<vm-public-ip>/ in a browser. Because DeepWiki has no login of its own, the instance answers anonymously with HTTP 401 and the browser asks for the username and password from Step 2.

The browser authentication prompt shown because the instance answers anonymous requests with HTTP 401

Once you are in, DeepWiki asks for a repository. Paste any public GitHub, GitLab or Bitbucket URL — or owner/repo shorthand.

The DeepWiki repository input behind the authentication gate

Choosing Generate Wiki opens the configuration panel. This is where you choose which provider and model spend your credits, whether you want a Comprehensive wiki (more pages, more model calls) or a Concise one, and the language to write it in.

The model configuration panel where the provider, model, wiki depth and language are chosen

DeepWiki then clones the repository, embeds it, works out a page structure and writes each page — streaming progress over the WebSocket as it goes. When it finishes you get a navigable wiki: a page tree on the left, generated prose in the middle, and Mermaid diagrams of the architecture rendered inline.

A generated wiki: the page tree, the AI written overview of the codebase, and an architecture diagram

Generated wikis are cached on the VM, so re-opening one is instant and costs nothing. They are listed on the home page when you come back.

Step 6 — Private repositories

DeepWiki can index private repositories. In the configuration panel, expand Add access tokens for private repositories and paste a personal access token with read access.

Two things are worth knowing about how this image handles that token:

  • Everything DeepWiki clones lives under /var/lib/deepwiki/.adalflow, which is mode 0750 and owned by the deepwiki service account. It is not world readable, and nginx never serves any filesystem path — it only proxies to the two application processes — so cloned private source is never reachable over HTTP.
  • When git clones with a token in the URL it writes that URL, token included, into the cloned repository's own .git/config. Upstream never removes it. This image runs deepwiki-scrub-repo-tokens.timer every minute, which strips the credential back out of the remote URL while leaving the URL itself intact.
systemctl is-active deepwiki-scrub-repo-tokens.timer
active

Step 7 — Prove the gate is fail closed

This is worth doing once on your own VM. Hide the credential file and try to start nginx:

sudo systemctl stop nginx
sudo mv /etc/nginx/deepwiki.htpasswd /root/deepwiki.htpasswd.bak
sudo systemctl start nginx || echo "nginx refused to start"
systemctl is-active nginx || echo "gate is fail closed: nginx will not serve without a credential"
nginx refused to start
gate is fail closed: nginx will not serve without a credential

nginx refuses to start rather than serving an unauthenticated instance. Put the file back:

sudo mv /root/deepwiki.htpasswd.bak /etc/nginx/deepwiki.htpasswd
sudo chown root:www-data /etc/nginx/deepwiki.htpasswd
sudo chmod 0640 /etc/nginx/deepwiki.htpasswd
sudo systemctl reset-failed nginx
sudo systemctl start nginx; systemctl is-active nginx
active

The fail closed gate refusing to start without a credential file, and the exact upstream commit this image ships

Step 8 — Change the sign in credential

The generated password is fine to keep, but you can set your own at any time:

sudo htpasswd -B /etc/nginx/deepwiki.htpasswd <DEEPWIKI_WEB_USERNAME>

It prompts for the new password twice, then reload nginx:

sudo systemctl reload nginx

Keep exactly one entry in that file. To rename the user, recreate the file with htpasswd -cB.

Step 9 — Verify what this image ships

The image records the exact upstream commit it was built from:

cat /opt/deepwiki/.cloudimg-provenance
# cloudimg build provenance for DeepWiki-Open on Ubuntu 24.04
product.name=DeepWiki-Open
product.upstream=https://github.com/AsyncFuncAI/deepwiki-open.git
product.commit=a562c789e72f211333042b360e42d479e8ed8791
product.licence=MIT
product.datastore=none (JSON wiki cache + in-process FAISS index on local disk)

Third party licences, including the one source adaptation cloudimg applies so the wiki generator works for remote browsers, are documented at:

cat /usr/share/doc/cloudimg/THIRD-PARTY-NOTICES

Maintenance

Where your data lives. Generated wikis, embedding indexes and cloned repositories are all under /var/lib/deepwiki/.adalflow. Back that directory up if you want to keep generated wikis; deleting it simply means the next visit regenerates them.

Logs.

sudo journalctl -u deepwiki-api -n 50 --no-pager
sudo journalctl -u deepwiki-web -n 50 --no-pager

Operating system updates are applied automatically by unattended-upgrades, which is enabled in this image.

Adding TLS. The image serves plain HTTP on port 80. For production, terminate HTTPS in front of the VM on Azure Application Gateway or Azure Front Door, or add your own certificate to /etc/nginx/sites-available/cloudimg-deepwiki and open port 443. The application is origin agnostic — the browser resolves the wiki generator socket from whatever origin served the page, so it follows an HTTPS front end automatically.

Costs. The VM is the small, predictable part. The variable cost is your AI provider: a comprehensive wiki for a large repository is many long model calls plus an embedding pass over the whole codebase. Start with Concise on a new repository to see what it costs you, and keep the instance behind its credential so nobody else is spending it.

Support

cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk.