-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add Docker deployment support #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
b741145
feat: add Docker deployment support
jfloresP88 d563934
fix: run NUT driver and upsd as root in Docker
jfloresP88 ffae676
fix: make Logs tab work in Docker without journald
jfloresP88 df360cd
fix: enable WOL device discovery in Docker via host networking
jfloresP88 985a5f5
fix: harden Docker USB access and NUT driver service resolution
jfloresP88 e86233c
fix: sharpen driver unit detection and stop-failure propagation
jfloresP88 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Git | ||
| .git | ||
| .github | ||
|
|
||
| # Python virtual environments | ||
| .venv | ||
| src/backend/.venv | ||
| src/backend/__pycache__ | ||
| src/backend/.pytest_cache | ||
| **/__pycache__ | ||
| **/.pytest_cache | ||
|
|
||
| # Frontend build intermediates | ||
| src/frontend/node_modules | ||
| src/frontend/dist | ||
|
|
||
| # Distribution artifacts | ||
| nutwatch.tar.gz | ||
|
|
||
| # Editor / local config | ||
| .opencode | ||
| .claude | ||
| .coderabbit.yaml | ||
| .playwright-cli | ||
| .vscode | ||
| .idea | ||
|
|
||
| # Documentation assets (not needed at runtime) | ||
| docs/screenshots |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # syntax=docker/dockerfile:1 | ||
|
|
||
| # Multi-stage build for NutWatch. | ||
| # Stage 1 builds the React frontend; Stage 2 is the runtime image with NUT. | ||
|
|
||
| FROM node:22-slim AS frontend-builder | ||
| # Build the React SPA. Vite writes to ../backend/static, so we copy the | ||
| # backend tree into the same relative location before building. | ||
| WORKDIR /build/src/frontend | ||
| COPY src/frontend/package.json src/frontend/package-lock.json ./ | ||
| RUN npm ci | ||
| COPY src/frontend/ ./ | ||
| COPY src/backend/ /build/src/backend/ | ||
| RUN npm run build | ||
|
|
||
| FROM ubuntu:24.04 | ||
|
|
||
| ENV DEBIAN_FRONTEND=noninteractive | ||
| ENV NUTWATCH_DIR=/opt/nutwatch | ||
| ENV NUTWATCH_HOST=0.0.0.0 | ||
| ENV NUTWATCH_PORT=8081 | ||
| ENV NUT_LISTEN_ADDR=0.0.0.0 | ||
| ENV NUT_LISTEN_PORT=3493 | ||
| ENV PYTHONUNBUFFERED=1 | ||
|
|
||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| nut-server \ | ||
| nut-client \ | ||
| usbutils \ | ||
| busybox-syslogd \ | ||
| iproute2 \ | ||
| iputils-arping \ | ||
| iputils-ping \ | ||
| python3 \ | ||
| python3-venv \ | ||
| supervisor \ | ||
| tini \ | ||
| curl \ | ||
| openssl \ | ||
| && rm -rf /var/lib/apt/lists/* \ | ||
| && rm -f /etc/nut/ups.conf /etc/nut/upsd.conf /etc/nut/upsd.users \ | ||
| /etc/nut/upsmon.conf /etc/nut/nut.conf \ | ||
| && rm -f /etc/syslog.conf | ||
|
|
||
| WORKDIR $NUTWATCH_DIR | ||
|
|
||
| # Copy backend application with freshly built frontend static files. | ||
| COPY --from=frontend-builder /build/src/backend/ $NUTWATCH_DIR/ | ||
|
|
||
| # Install Python dependencies. | ||
| RUN python3 -m venv $NUTWATCH_DIR/venv \ | ||
| && $NUTWATCH_DIR/venv/bin/pip install --no-cache-dir -r $NUTWATCH_DIR/requirements.txt | ||
|
|
||
| # Copy Docker runtime helpers. | ||
| COPY scripts/docker/entrypoint.sh /entrypoint.sh | ||
| COPY scripts/docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf | ||
| COPY scripts/docker/systemctl-shim.sh /usr/local/bin/systemctl | ||
| COPY scripts/docker/upsmon-wrapper.sh /usr/local/bin/upsmon-wrapper | ||
|
|
||
| RUN chmod +x /entrypoint.sh /usr/local/bin/systemctl /usr/local/bin/upsmon-wrapper \ | ||
| && mkdir -p /etc/nut/notify.d /var/log/nut /var/run/nut /var/lib/nutwatch /var/log/supervisor \ | ||
| && chown -R root:nut /etc/nut \ | ||
| && chmod 750 /etc/nut /etc/nut/notify.d \ | ||
| && chown nut:nut /var/log/nut /var/run/nut \ | ||
| && chmod 755 /var/lib/nutwatch | ||
|
|
||
| # Persist NUT configuration and NutWatch data (accounts, history, API keys). | ||
| VOLUME ["/etc/nut", "/var/lib/nutwatch"] | ||
|
|
||
| EXPOSE 8081 3493 | ||
|
|
||
| ENTRYPOINT ["/usr/bin/tini", "--"] | ||
| CMD ["/entrypoint.sh"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| MIT License | ||
|
|
||
| Copyright (c) 2026 nutwatch contributors | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| services: | ||
| nutwatch: | ||
| build: . | ||
| container_name: nutwatch | ||
| # USB access: mount the host USB bus and allow USB character devices via | ||
| # the device cgroup. The cgroup rule is evaluated when devices appear, so | ||
| # UPS hotplug works without privileged mode. Trust boundary: the container | ||
| # can then drive every USB device on the host bus. To scope it down, | ||
| # replace the mount with a specific /dev/bus/usb/<bus>/<dev> device when | ||
| # your UPS always reappears at the same path. | ||
| devices: | ||
| - /dev/bus/usb:/dev/bus/usb | ||
| device_cgroup_rules: | ||
| - 'c 189:* rwm' | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| # Fallback: replace the two blocks above with `privileged: true` if USB | ||
| # access still fails on your setup. | ||
| # Share the host network stack: WOL device discovery needs the LAN's ARP | ||
| # table, and magic-packet broadcasts must reach the physical network. | ||
| # With host networking, `ports:` is ignored; NutWatch serves directly on | ||
| # host ports 8081 (UI) and 3493 (NUT). Note: until the first admin | ||
| # account is created on the Setup page, the UI is open — run the first | ||
| # `docker compose up` on a trusted network and finish setup promptly. | ||
| network_mode: host | ||
|
JuanCF marked this conversation as resolved.
|
||
| volumes: | ||
| - nutwatch-config:/etc/nut | ||
| - nutwatch-data:/var/lib/nutwatch | ||
| environment: | ||
| - NUT_UPS_NAME=ups | ||
| - NUT_UPS_DESC=My UPS | ||
| - NUT_DRIVER=usbhid-ups | ||
| - NUT_ADMIN_USER=admin | ||
| - NUT_MONITOR_USER=monuser | ||
| # Optional. Credentials are generated on first start and persisted in | ||
| # the nutwatch-config volume. Set these before the first | ||
| # `docker compose up` to use your own: | ||
| # - NUT_ADMIN_PASS=your-admin-password | ||
| # - NUT_MONITOR_PASS=your-monitor-password | ||
| # Optional. Flask session signing key (>= 32 characters). If unset, the | ||
| # backend generates a random key and persists it in nutwatch-data. | ||
| # - NUTWATCH_SECRET_KEY=your-long-random-secret | ||
| restart: unless-stopped | ||
|
|
||
| volumes: | ||
| nutwatch-config: | ||
| nutwatch-data: | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.