Skip to content

build(docker): add Dockerfile for building a server image - #641

Merged
ErikBjare merged 3 commits into
ActivityWatch:masterfrom
smart-runus:feat/docker-image
Aug 10, 2026
Merged

build(docker): add Dockerfile for building a server image#641
ErikBjare merged 3 commits into
ActivityWatch:masterfrom
smart-runus:feat/docker-image

Conversation

@almirb

@almirb almirb commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Multi-stage build: compiles aw-webui and aw-server, then ships only the release binary on debian:bookworm-slim with libssl3.

Only aw-server is built, not aw-sync: on Linux the latter pulls in openssl with the "vendored" feature and compiles OpenSSL from source, which is not needed by the image.

Multi-stage build: compiles aw-webui and aw-server, then ships only the
release binary on debian:bookworm-slim with libssl3.

Only aw-server is built, not aw-sync: on Linux the latter pulls in openssl
with the "vendored" feature and compiles OpenSSL from source, which is not
needed by the image.
Comment thread Dockerfile Outdated
RUN apt-get update -qq -y && \
apt-get install -qq -y --no-install-recommends \
build-essential pkg-config libssl-dev ca-certificates curl git make gnupg && \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Unverified installer controls build artifacts

When the floating NodeSource endpoint is compromised, intercepted, or changed unexpectedly, its response executes directly as root in the builder stage and can modify the server or web assets copied into the runtime image, causing the published image to contain unreviewed code. How this was verified: The remote response runs before make aw-server in the same builder stage whose outputs are copied into the final image.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread Dockerfile Outdated

EXPOSE 5600

CMD ["aw-server-rust"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 security Server runs as root

The runtime stage has no USER directive, so the documented network-facing server and its datastore operations run as UID 0; this unnecessarily expands the impact of a process compromise and creates root-owned files on bind-mounted storage. How this was verified: The final stage launches aw-server-rust without changing users, and the application does not drop privileges.

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Greptile Summary

Adds a documented multi-stage Docker build for aw-server-rust.

  • Builds the web UI with Node and compiles the server in a Rust builder stage.
  • Produces a slim Debian runtime image containing the server binary and required OpenSSL library.
  • Runs the server as an unprivileged UID/GID 10001 user with persistent-data guidance.
  • Excludes local build artifacts and dependency directories from the Docker context.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the floating installer was replaced with an official Node image, and the runtime now launches under the unprivileged aw user with writable HOME-based application paths.

Important Files Changed

Filename Overview
scripts/Dockerfile Adds a multi-stage Node/Rust build and a minimal non-root Debian runtime image, resolving both previously reported security concerns.
README.md Documents image construction, container startup, network binding, non-root volume ownership, persistence, migration, and cross-platform builds.
.dockerignore Excludes generated artifacts, dependency trees, coverage output, and local tooling state from the Docker build context.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    S[Source tree and initialized aw-webui submodule] --> N[Node 22 stage]
    N -->|Node and npm| B[Rust builder stage]
    B -->|make aw-server| A[Release server binary with embedded web UI]
    A --> R[Debian Bookworm slim runtime]
    R --> U[Run as unprivileged user aw]
    U --> D[(Persistent ActivityWatch datastore)]
Loading

Reviews (2): Last reviewed commit: "Merge branch 'ActivityWatch:master' into..." | Re-trigger Greptile

@ErikBjare

Copy link
Copy Markdown
Member

We have rejected similar PRs in the past, as the Dockerfiles aren't being used by maintainers or in CI and so not something we want to maintain or bless/suggest we support.

If you explain your usecase I might change my mind.

@almirb

almirb commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

We have rejected similar PRs in the past, as the Dockerfiles aren't being used by maintainers or in CI and so not something we want to maintain or bless/suggest we support.

If you explain your usecase I might change my mind.

Fair enough — I understand not wanting to bless or maintain something you
don't use. Let me describe the use case, and also scope down what I'm
actually asking for.

Use case: I run aw-server-rust as an always-on central instance on a
headless Ubuntu server, aggregating data from [N] machines that sync into
it. This is essentially the setup aw-sync's README already describes (a
central instance + multidevice query), just permanent rather than a
temporary testing instance. On a headless server managed by Portainer,
a container is the natural unit of deployment — there is no aw-qt, no
desktop session, no user systemd unit to hang it off.

Why this might matter to the project: the absence of a Dockerfile
doesn't mean people don't run this in Docker — it means they run someone
else's image. I was pulling brain40/aw-server-rust:latest from Docker
Hub for months: an opaque binary, built by a stranger, from unknown
source, handling all of my activity data. For a project whose entire
value proposition is privacy and data ownership, pushing self-hosters
toward unauditable third-party images seems like the worse outcome. A
Dockerfile in-tree lets people build it themselves and verify what they
run.

What I'm not asking for: no official image on Docker Hub, no release
pipeline, no support promise, no badge in the README. Just the build
recipe in-tree.

To address the maintenance concern, I'm happy to do any of:

  • Mark it explicitly as community-contributed and unsupported in the
    README, so it carries no implication of official support.
  • Put it under contrib/ instead of the repo root.

One thing the containerized build surfaced, incidentally: make build
fails in a clean environment because aw-sync pulls in openssl with the
vendored feature (#478) and compiles OpenSSL from source. My Dockerfile
sidesteps it by building only the aw-server target. A clean-room build
tends to expose this kind of friction that a developer machine hides.

If the answer is still no, that's completely fine — I'll keep it in my
fork. In that case, would you be open to a line in the docs pointing to
community-maintained images? That's zero maintenance for you and still
better than people finding random images on Docker Hub.

That's a very nice project! Congrats!

@ErikBjare

Copy link
Copy Markdown
Member

@almirb Putting it in scripts/ would be good, also addressing Greptile's findings. I'll accept it if fixed, I agree it's better to have some kind of official reference which we can iron out the worst mistakes in.

@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.96%. Comparing base (656f3c9) to head (6256e34).
⚠️ Report is 86 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #641      +/-   ##
==========================================
+ Coverage   70.81%   75.96%   +5.14%     
==========================================
  Files          51       63      +12     
  Lines        2916     5105    +2189     
==========================================
+ Hits         2065     3878    +1813     
- Misses        851     1227     +376     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

almirb added 2 commits August 10, 2026 11:06
Get Node from the official image instead of piping the NodeSource setup
script into a root shell: nothing fetched at build time now runs as root
in the stage whose artifacts end up in the final image.

Run the server as the unprivileged user `aw` (uid/gid 10001) instead of
root, which moves the datastore to /home/aw/.local/share/activitywatch.

Move the Dockerfile into scripts/ and update the README accordingly.
@almirb

almirb commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

@almirb Putting it in scripts/ would be good, also addressing Greptile's findings. I'll accept it if fixed, I agree it's better to have some kind of official reference which we can iron out the worst mistakes in.

Done! Could you check it again?

Thanks!

@ErikBjare

Copy link
Copy Markdown
Member

@greptileai review

@ErikBjare
ErikBjare merged commit b2e2dee into ActivityWatch:master Aug 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants