Alfresco Community Edition on Ubuntu 24.04 on Azure User Guide
Overview
Alfresco Community Edition is an open source enterprise content management platform. It gives an organisation one governed home for its documents, with version history, folder structure, metadata and permissions that can be applied per site, per folder or per document.
People work through the Share web interface, where content is organised into collaboration sites with document libraries. The repository indexes both the metadata and the full text of documents, so a file is found by what it says and not only by what it was named. A comprehensive ReST API and the CMIS standard let other applications build on the same content store.
This image wires the whole stack together and generates every built in secret afresh on the VM you launch.
What is included:
- Alfresco Community Edition 26.1.0 repository on Apache Tomcat 10.1.57
- Alfresco Share web interface
- Alfresco Search Services 2.0.21 (Solr 6.6.5-patched.22) with full text indexing
- PostgreSQL 16 as the repository database
- OpenJDK 21
- nginx on port 80 as the only public surface
- Ubuntu 24.04 LTS base, fully patched at build time
- 24/7 cloudimg support, 24h response SLA
Scope, stated plainly. This is the Community Edition: no clustering, no records management and no vendor support SLA. This image also does not ship the Transform Service or its T-Engines, which are the components that render thumbnails and preview images. Documents are stored, versioned, permissioned, searched by their content and downloaded byte for byte, but Share shows a generic file icon rather than a rendered preview. That trade is deliberate: the transform stack is a set of Docker containers that would roughly double the memory floor and pull a container runtime into the image.
Prerequisites
- An active Azure subscription.
- An SSH key pair.
- A VNet and subnet to deploy into.
- A network security group you can edit, to restrict who reaches ports 22 and 80.
Recommended VM size: Standard_D4s_v5 (4 vCPU / 16 GB). Alfresco is a two JVM Java stack plus PostgreSQL, and this size is where it has real headroom rather than merely running. The image sizes both heaps automatically from the memory it finds at first boot, so smaller sizes do work for evaluation: a Standard_B2s (2 vCPU / 4 GB) runs the full stack with roughly 1.5 GB still free. Treat D4s_v5 as headroom for real document volumes and concurrent users, not as a hard floor.
Step 1: Deploy from the Azure Portal
Search the Marketplace for Alfresco Community Edition, choose the plan and deploy it into your VNet. In the network security group, allow TCP 22 (SSH) and TCP 80 (Share) from your own networks only. In production, put a TLS terminating reverse proxy or an Azure Application Gateway in front of port 80.
Step 2: Deploy from the Azure CLI
RG="alfresco-prod"; LOCATION="eastus"; VM_NAME="alfresco-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/alfresco-community-edition-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name alf-vnet --address-prefix 10.104.0.0/16 --subnet-name alf-subnet --subnet-prefix 10.104.1.0/24
az network nsg create -g "$RG" --name alf-nsg
az network nsg rule create -g "$RG" --nsg-name alf-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name alf-nsg --name allow-web --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
--size Standard_D4s_v5 --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name alf-vnet --subnet alf-subnet --nsg alf-nsg --public-ip-sku Standard
Step 3: Connect via SSH
ssh azureuser@<vm-ip>
The first boot generates every secret this image uses and then starts the repository and the search service. On a Standard_D4s_v5 the stack is ready a couple of minutes after the VM reports running; on a smaller size allow a little longer.
Step 4: Verify the Services
for u in postgresql alfresco-search alfresco nginx; do printf '%-18s : %s\n' "$u" "$(systemctl is-active $u)"; done
sudo test -f /var/lib/cloudimg/alfresco-firstboot.done && echo "firstboot sentinel : present"
sudo ss -tln | grep -E ':8080|:8983|:5432|:80 '
curl -s -o /dev/null -w 'Solr through nginx: HTTP %{http_code}\n' http://127.0.0.1/solr/
Only nginx is bound to a public address. The repository (8080), Solr (8983) and PostgreSQL (5432) all listen on loopback, and nginx deliberately refuses /solr/ with HTTP 403 so the Solr admin console is never reachable from outside the VM.

Step 5: Retrieve the Administrator Password
sudo cat /root/alfresco-credentials.txt
sudo stat -c '%a %U:%G' /root/alfresco-credentials.txt
The file is mode 0600 and readable only by root. It contains the Share URL, the administrator username and a password unique to this VM.
The upstream admin/admin default is never created on this image. Alfresco ships a properties file containing the hash of the password admin. At first boot this image computes the hash of your per VM password and writes it in place before the repository has ever started, so the default account does not exist and is not merely rotated afterwards. You can confirm it is refused:
curl -s -o /dev/null -w 'admin/admin -> HTTP %{http_code}\n' -u admin:admin \
http://127.0.0.1:8080/alfresco/api/-default-/public/alfresco/versions/1/people/-me-
curl -s -o /dev/null -w 'unauthenticated -> HTTP %{http_code}\n' \
http://127.0.0.1:8080/alfresco/api/-default-/public/alfresco/versions/1/people/-me-
Both return HTTP 401.

Four separate secrets are generated per VM: the administrator password, the PostgreSQL role password, the shared secret the repository and Solr use to authenticate to each other, and the metadata keystore. That last one matters more than it sounds: the keystore password shipped in an Alfresco download is identical in every copy of that download worldwide, so an image that kept it would be protecting its metadata with a publicly known key.
Step 6: Upload a Document and Find It by Its Content
This is the round trip that proves the stack is genuinely working rather than merely running. Note that the word searched for below appears only inside the document, never in its filename, so a hit can only come from full text indexing.
PW=$(sudo awk -F': *' '/^Password/{print $2; exit}' /root/alfresco-credentials.txt)
API=http://127.0.0.1:8080/alfresco/api/-default-/public/alfresco/versions/1
SEARCH=http://127.0.0.1:8080/alfresco/api/-default-/public/search/versions/1/search
printf 'Quarterly Report\n\nQ3 revenue rose sharply across the ANNUALSUMMARYALPHA division.\n' > /tmp/quarterly-report.txt
NODE=$(curl -sf -u "admin:$PW" -X POST "$API/nodes/-shared-/children" \
-F filedata=@/tmp/quarterly-report.txt -F name=quarterly-report.txt \
-F nodeType=cm:content -F overwrite=true \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["entry"]["id"])')
echo "node id: $NODE"
# Search is eventually consistent: Solr tracks the repository on a poll cycle and
# text extraction adds a step, so allow up to a minute or so on a small VM.
for i in $(seq 1 60); do
HITS=$(curl -sf -u "admin:$PW" -X POST "$SEARCH" -H 'Content-Type: application/json' \
-d '{"query":{"language":"afts","query":"TEXT:\"ANNUALSUMMARYALPHA\""}}' \
| python3 -c 'import sys,json; print(json.load(sys.stdin)["list"]["pagination"]["count"])')
[ "$HITS" != "0" ] && { echo "found by full text search after ~$((i*5))s: $HITS hit(s)"; break; }
sleep 5
done
curl -sf -u "admin:$PW" "$API/nodes/$NODE/content" -o /tmp/downloaded.txt
sha256sum /tmp/quarterly-report.txt /tmp/downloaded.txt
The two checksums match, because the repository returns the bytes it was given.

Step 7: Sign In to Share
Browse to http://<vm-ip>/share/ and sign in as admin with the password from /root/alfresco-credentials.txt.

The dashboard collects your sites, your activities, your tasks and the documents you touched most recently:

Step 8: Browse the Repository
Repository in the toolbar opens the whole content tree. The Shared folder is a good place to start, and the document uploaded in step 6 is already there:

Opening a document shows its details, its version number and the full set of actions: edit properties, upload a new version, manage permissions, start a workflow, move, copy or delete.
Because this image ships no transform engine, the preview pane says the document cannot be previewed and offers a download instead. That is expected and is the documented trade described in the Overview. Everything else about the document, including its version history and its full text searchability, works normally.

Step 9: Search from the Interface
Type a word into the search box at the top right. The results view searches the content of documents, not just their names, and highlights the matched term in the extracted text:

The left hand facets narrow results by creator, file type, size and date. Search Manager, on the right, lets an administrator configure the available facets.
Step 10: Server Components
java -version
sudo ls -1 /opt/alfresco/tomcat/webapps/ | grep -v '\.war$'
sudo -u postgres psql -tAc 'select version()'

| Component | Path |
|---|---|
| Alfresco home | /opt/alfresco |
| Tomcat | /opt/alfresco/tomcat |
| Repository configuration | /opt/alfresco/tomcat/shared/classes/alfresco-global.properties |
| Content store | /opt/alfresco/alf_data |
| Metadata keystore | /opt/alfresco/keystore |
| Search service | /opt/alfresco-search-services |
| Repository log | /opt/alfresco/tomcat/alfresco.log |
| Search log | /opt/alfresco-search-services/logs/solr.log |
| nginx site | /etc/nginx/sites-available/cloudimg-alfresco |
| Credentials | /root/alfresco-credentials.txt (mode 0600) |
| Firstboot sentinel | /var/lib/cloudimg/alfresco-firstboot.done |
| Port | Bound to | Purpose |
|---|---|---|
| 80 | all interfaces | nginx, the only public surface |
| 8080 | 127.0.0.1 | Tomcat: the repository and Share |
| 8983 | 127.0.0.1 | Alfresco Search Services |
| 5432 | 127.0.0.1 | PostgreSQL |
Step 11: Managing the Services
Start them in dependency order and stop them in reverse. The repository will not serve requests until PostgreSQL is up, and search results lag until the search service has caught up.
sudo systemctl restart alfresco-search.service
sudo systemctl restart alfresco.service
sudo journalctl -u alfresco.service --no-pager -n 50
sudo tail -n 50 /opt/alfresco/tomcat/alfresco.log
When Tomcat stops the Share application it logs a block of SEVERE ... checkThreadLocalMapForLeaks messages naming FreeMarker, Spring and Slingshot classes. These are emitted during shutdown, they are normal for Alfresco Share on Tomcat, and they do not indicate a failed restart. Judge a restart by the readiness probe below, not by the absence of SEVERE in the shutdown log.
The repository answers its readiness probe within a few seconds of a restart, but the search service is still re establishing its tracking at that point and text extraction is at its slowest. If a document uploaded immediately after a restart is not searchable yet, give it a minute before concluding anything is wrong:
curl -s -o /dev/null -w 'ready probe: HTTP %{http_code}\n' \
http://127.0.0.1:8080/alfresco/api/-default-/public/alfresco/versions/1/probes/-ready-
Step 12: Security Recommendations
- Change the administrator password in Share, under the account menu at the top right, and store the new value in your own secret manager.
- Restrict the network security group so that ports 22 and 80 only accept traffic from networks you control.
- Terminate TLS in front of nginx. The image serves plain HTTP on port 80 so that it makes no assumptions about your certificate authority. Put an Application Gateway, a load balancer or a TLS reverse proxy in front of it before any real content goes in.
- Create named user accounts in Share rather than sharing the administrator login, and grant permissions per site or per folder.
- Back up both halves of the repository together. The PostgreSQL database and the content store at
/opt/alfresco/alf_dataare a matched pair, and a backup of one without the other does not restore. - Keep the OS patched with
sudo apt-get update && sudo apt-get upgrade, and reboot for kernel updates.
Step 13: Support and Licensing
Alfresco Community Edition is published under the LGPL-3.0 licence. One bundled third party component, junrar, is distributed under the UnRAR licence, which permits redistribution inside another software package but is not an OSI approved licence, so this image is not wholly OSI licensed. cloudimg provides commercial support for the image itself, separately from the upstream project.
- Email: support@cloudimg.co.uk
- Website: www.cloudimg.co.uk
- Support hours: 24/7, 24h response SLA
Deploy on Azure
Launch Alfresco Community Edition on Ubuntu 24.04 with 24/7 support from cloudimg.
View on Marketplace
Need Help?
Our support team is available 24/7. support@cloudimg.co.uk