Storage Azure

Alfresco Community Edition on Ubuntu 24.04 on Azure User Guide

| Product: Alfresco Community Edition on Ubuntu 24.04 LTS on Azure

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

  1. An active Azure subscription.
  2. An SSH key pair.
  3. A VNet and subnet to deploy into.
  4. 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.

postgresql, alfresco-search, alfresco and nginx all active; the firstboot sentinel present; the repository, Solr and PostgreSQL bound to loopback while only nginx listens publicly; and the Solr admin UI refused with HTTP 403 through nginx

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.

the per VM credentials file at /root/alfresco-credentials.txt with the password masked, mode 0600 root root, and both the upstream admin/admin login and an unauthenticated request refused with 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.

a document uploaded through the ReST API, then found by a full text search for a word that appears only in the document body, then downloaded again with a byte identical sha256

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 Alfresco Share sign in page showing the Alfresco Community Edition branding with User Name and Password fields

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

the Administrator dashboard in Alfresco Share showing the My Sites, My Activities, My Tasks and My Documents dashlets, with the recently uploaded quarterly report listed

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:

the Alfresco Share repository browser open on the Shared folder, listing the quarterly report document with its size and modification details

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.

the document details page for the quarterly report showing version 1.2, the full document actions list, and the preview pane explaining that the document cannot be previewed and offering a download

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:

Alfresco Share search results for a term that appears only inside the document body, showing one result with the matching phrase highlighted in the extracted content snippet

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()'

the Java, Tomcat, PostgreSQL and Alfresco Search Services versions, the deployed ROOT, alfresco and share web applications, and confirmation that no ActiveMQ or transform unit is present and no server side renditions are produced

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_data are 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