I tried running HOOPS AI V1.1 headless on Ubuntu 24.04 (EC2)

I tried running HOOPS AI V1.1 headless on Ubuntu 24.04 (EC2)

HOOPS AI V1.1 added Linux support, which is great news if you’re deploying to servers instead of workstations. But most server deployments are headless — no display attached — and Linux support doesn’t necessarily mean headless Linux support. So I wanted to find out: can you actually run it on a headless box today?

Short answer: it runs. Here’s how.

Status note: Linux is supported as of V1.1. The main thing to know is that license validation and inference still expect an OpenGL/display context to exist, so you’ll need Xvfb to satisfy that on a box with no real display attached. Here’s exactly what that looked like for me.

1. Launch the EC2 instance

  • AMI: Ubuntu Server 24.04 LTS (HVM)
  • Instance type: choose based on your inference workload (GPU instance if you’re running MFR inference at scale; a general-purpose instance is fine for light/dev use)
  • Storage: size according to your CAD dataset + FAISS index size
  • Security group: open only the ports you actually need exposed. If your HOOPS AI instance holds confidential 3D model data or proprietary ML training data, don’t open those ports to 0.0.0.0/0 (all IPs) — restrict access to your own IP range, a VPN, or a bastion host instead

SSH in once it’s running:

ssh -i your-key.pem ubuntu@<instance-public-ip>

2. Install required system packages

HOOPS AI needs OpenGL and offscreen rendering libraries even when nothing will ever be displayed:

sudo apt-get update && sudo apt-get install -y libglu1-mesa libgl1 libosmesa6 xvfb python3.12-venv p7zip-full

Package Why it’s needed
libglu1-mesa, libgl1 OpenGL runtime libraries HOOPS AI links against
libosmesa6 Offscreen Mesa rendering (software GL, no GPU/X server needed for rendering itself)
xvfb Virtual framebuffer X server — lets HOOPS AI think a real display exists
python3.12-venv Needed to create an isolated virtual environment for the HOOPS AI install (Ubuntu 24.04 ships Python 3.12, and the system Python is externally-managed, so venv is required)
p7zip-full Some assets/sample data used by the WebAPI Sandbox are distributed as .7z archives, which aren’t extractable with the default Ubuntu toolset

3. Create the install directory and set ownership

Create the directory HOOPS AI will be installed into, then make sure your non-root user actually owns it — otherwise later steps (venv creation, package install, runtime writes) will hit permission errors:

sudo mkdir -p /var/HOOPS_AI/
sudo chown -R ubuntu:ubuntu /var/HOOPS_AI/

4. Install HOOPS AI itself

With the install directory ready and owned by your user, set up a venv and install HOOPS AI into it:

cd /var/HOOPS_AI/
python3.12 -m venv .venv
source .venv/bin/activate
# pip install <your HOOPS AI wheel/package here>

Get the Tutorial Data Assets

The SDK install doesn’t include the trained model files used by the tutorials/sandbox — those come as a separate download, the Tutorial Data Assets package. You’ll need this for things like the pretrained MFR model (packages\trained_ml_models\ts3d_162k_mfr.ckpt).

Get the Tutorial Data Assets package separately, then place the whole packages folder under your HOOPS AI install directory:

# after downloading/extracting the Tutorial Data Assets package
mv packages /var/HOOPS_AI/packages

So you end up with, for example, /var/HOOPS_AI/packages/trained_ml_models/ts3d_162k_mfr.ckpt.

Clone the WebAPI Sandbox

Instead of working through the raw tutorial notebooks, I switched to the HOOPS AI WebAPI Sandbox — a ready-to-run sandbox for exercising the HOOPS AI Web API:

sudo git clone https://github.com/toshi-bata/hoops_ai_webapi_sandbox.git /var/hoops_ai_webapi_sandbox
sudo chown -R ubuntu:ubuntu /var/hoops_ai_webapi_sandbox

(The clone itself doesn’t need sudo once /var/hoops_ai_webapi_sandbox’s parent is writable by your user — but if you do run it with sudo as above, don’t skip the chown, or you’ll end up with root-owned files that cause permission errors later.)

Set up the environment by following the sandbox’s own README (dependencies, .env config, etc. — nothing headless-specific at this stage).

Starting the server headless

The sandbox’s normal startup command assumes a display is available. On a headless server, start a virtual display with Xvfb first, then launch the server with DISPLAY pointed at it:

cd /var/hoops_ai_webapi_sandbox
Xvfb :99 -screen 0 1280x960x24 &
DISPLAY=:99 /var/HOOPS_AI/.venv/bin/python main.py --host 0.0.0.0 --port 8000

Confirming it worked

If the setup is correct, the server startup log should include something like this:

------------------------------------------------------------
HOOPS AI
------------------------------------------------------------
  Platform      : Linux 6.17.0-1017-aws
  Architecture  : x86_64
  Python        : 3.12.3
------------------------------------------------------------
  Core          : hoops-ai             1.1.0  (build: ed23c84 2026-06-12T13:13:31Z)
  CAD Access    : hoops-exchange       26.2.0  (build: 1e11169 2026-06-12T10:36:38Z)
  Conversion    : hoops-converter      26.1.1  (build: 00dc9f6 2026-06-12T10:22:46Z)
  Insights      : hoops-web-viewer     26.1.1  (build: d30058f 2026-06-12T10:22:25Z)
------------------------------------------------------------
======================================================================
[OK] HOOPS AI License: Valid
======================================================================
[hoops_ai] License initialized.
INFO:     Application startup complete.

The line to look for is [OK] HOOPS AI License: Valid — that’s your confirmation that both the license and the headless display setup are working correctly.

After that, you may see a batch of XKEYBOARD warnings like:

The XKEYBOARD keymap compiler (xkbcomp) reports:
> Warning:          Could not resolve keysym XF86CameraAccessEnable
...
Errors from xkbcomp are not fatal to the X server

These are safe to ignore — they’re just Xvfb’s keymap compiler complaining about keyboard keys that don’t matter on a headless server with no physical keyboard attached. They don’t affect the server.

5. Test it from another machine

Once the server is up, the best way to confirm everything actually works end-to-end is to call the REST API — ideally from a different machine than the EC2 instance itself, so you’re testing it the way a real client would.

The sandbox repo has example calls; here are the two I used to sanity-check things, run from Windows using curl.exe:

Upload a CAD file and get back B-rep info:

curl.exe -X POST http://<your-instance-ip>:8000/cad/load -F "file=@C:\temp\nist_ftc_06_asme1_rd_sw1802.SLDPRT"

{"filename":"4042ab786f8e4a1ab5903e4ae840a689_nist_ftc_06_asme1_rd_sw1802.SLDPRT","faces":{"count":144,"types":[0, ...

Run MFR inference on the same file:

curl.exe -X POST http://<your-instance-ip>:8000/mfr/inference -F "file=@C:\temp\nist_ftc_06_asme1_rd_sw1802.SLDPRT"

{"filename":"a42285e284b247e0b6b3df7243b0981e_nist_ftc_06_asme1_rd_sw1802.SLDPRT","face_count":144,"predictions":[0, ...

If both calls return a JSON response like this, the setup is working correctly. (And as a reminder from the EC2 setup step — if you’re testing from outside the instance like this, make sure port 8000 is only opened to your own IP in the security group, not 0.0.0.0/0, especially if the CAD files involved are confidential.)

6. Run it as a systemd service (non-root)

Once you’ve confirmed it works, running it manually in your shell every time isn’t great for anything long-running. Wrap it in a systemd service instead — and run it as a non-root user (User=ubuntu, matching the ownership you set up in step 3) so file permissions stay consistent across restarts.

Xvfb (virtual display) must run as a separate service, because ExecStartPre waits for the command to exit — a long-running process like Xvfb would cause a timeout.

First, create the Xvfb service:

 # /etc/systemd/system/xvfb.service
 [Unit]
 Description=Virtual Framebuffer X Server
 After=network.target
 
 [Service]
 Type=simple
 ExecStart=/usr/bin/Xvfb :99 -screen 0 1280x960x24
 Restart=on-failure
 
 [Install]
 WantedBy=multi-user.target

Then create the WebAPI service, declaring a dependency on Xvfb:

 # /etc/systemd/system/hoops-ai-sandbox.service
 [Unit]
 Description=HOOPS AI WebAPI Sandbox
 After=network.target xvfb.service
 Requires=xvfb.service
 
 [Service]
 Type=simple
 User=ubuntu
 WorkingDirectory=/var/hoops_ai_webapi_sandbox
 Environment=DISPLAY=:99
 ExecStart=/var/HOOPS_AI/.venv/bin/python main.py --host 0.0.0.0 --port 8000
 Restart=on-failure
 
 [Install]
 WantedBy=multi-user.target

Enable and start both services:

 sudo systemctl daemon-reload
 sudo systemctl enable --now xvfb.service
 sudo systemctl enable --now hoops-ai-sandbox.service
 sudo systemctl status hoops-ai-sandbox.service

Summary

Step Required?
Install libglu1-mesa libgl1 libosmesa6 xvfb python3.12-venv p7zip-full Yes
Create install dir and chown -R ubuntu:ubuntu it Yes — avoids permission errors during install/runtime
Start Xvfb + set DISPLAY Yes — license validation/inference won’t start without it
Test via REST API from another machine Recommended — confirms the setup end-to-end
Run service as non-root user Yes — keeps file permissions consistent

If you want more detail on how the WebAPI Sandbox itself is built, I wrote that up separately in Wrapping HOOPS AI as a REST API with FastAPI.

Verdict

It runs once Xvfb is in the picture — that part’s straightforward, and otherwise it’s a clean path from EC2 instance to working API.

Happy to answer questions or share my exact systemd unit / install steps if useful — let me know in the comments.

1 Like