initial commit
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
# ── Stage 1: Build React app ──────────────────────────────────────────────────
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Copy audiocontrol source (place the audiocontrol/ folder next to docker-compose.yml)
|
||||
COPY audiocontrol/package*.json ./
|
||||
RUN npm ci --quiet
|
||||
|
||||
COPY audiocontrol/ ./
|
||||
RUN npm run build
|
||||
|
||||
# ── Stage 2: Nginx (serves app + proxies APIs) ────────────────────────────────
|
||||
FROM nginx:1.27-alpine
|
||||
|
||||
ARG BEOCREATE_HOST=beocreate.local
|
||||
ARG BEOCREATE_PORT=13141
|
||||
|
||||
# Copy built React app
|
||||
COPY --from=builder /build/dist /var/www/audiocontrol
|
||||
|
||||
# Generate nginx.conf with the BeoCreate address substituted
|
||||
COPY frontend/nginx.conf.template /etc/nginx/templates/default.conf.template
|
||||
|
||||
# nginx-envsubst will substitute $BEOCREATE_HOST and $BEOCREATE_PORT at startup
|
||||
ENV BEOCREATE_HOST=${BEOCREATE_HOST}
|
||||
ENV BEOCREATE_PORT=${BEOCREATE_PORT}
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
HEALTHCHECK --interval=15s --timeout=3s \
|
||||
CMD wget -qO- http://127.0.0.1/ || exit 1
|
||||
@@ -0,0 +1,105 @@
|
||||
# Nginx config — audiocontrol frontend
|
||||
# Variables substituted at container start via envsubst:
|
||||
# $BEOCREATE_HOST — hostname/IP of the BeoCreate Pi
|
||||
# $BEOCREATE_PORT — hifiberrydsp REST API port (default 13141)
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
# Docker's internal DNS — resolves all upstreams lazily so nginx starts
|
||||
# even if a backend is temporarily unreachable at boot
|
||||
resolver 127.0.0.11 valid=10s ipv6=off;
|
||||
|
||||
# ── Serve React SPA ──────────────────────────────────────────────────────
|
||||
root /var/www/audiocontrol;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# ── HiFiBerry DSP REST API (BeoCreate Pi) ────────────────────────────────
|
||||
location /api/hifiberry/ {
|
||||
set $beocreate http://${BEOCREATE_HOST}:${BEOCREATE_PORT};
|
||||
rewrite ^/api/hifiberry/(.*)$ /$1 break;
|
||||
proxy_pass $beocreate;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
proxy_connect_timeout 5s;
|
||||
}
|
||||
|
||||
# ── Mopidy JSON-RPC (HTTP) ───────────────────────────────────────────────
|
||||
location /api/mopidy/ {
|
||||
set $mopidy http://mopidy:6680;
|
||||
rewrite ^/api/mopidy/(.*)$ /mopidy/$1 break;
|
||||
proxy_pass $mopidy;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
|
||||
# ── Mopidy library images ───────────────────────────────────────────────
|
||||
location /api/mopidy-image/ {
|
||||
set $mopidy http://mopidy:6680;
|
||||
rewrite ^/api/mopidy-image/(.*)$ /$1 break;
|
||||
proxy_pass $mopidy;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
|
||||
# ── Mopidy WebSocket (real-time events) ──────────────────────────────────
|
||||
location /ws/mopidy {
|
||||
set $mopidy_ws http://mopidy:6680;
|
||||
proxy_pass $mopidy_ws/mopidy/ws;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
}
|
||||
|
||||
# ── Snapcast JSON-RPC (HTTP) ─────────────────────────────────────────────
|
||||
location /api/snapcast/rpc {
|
||||
set $snapserver_http http://snapserver:1780;
|
||||
rewrite ^/api/snapcast/rpc$ /jsonrpc break;
|
||||
proxy_pass $snapserver_http;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
|
||||
# ── Snapcast now playing recognition ─────────────────────────────────────
|
||||
# host.docker.internal lives in /etc/hosts (extra_hosts), not in Docker's
|
||||
# embedded DNS (127.0.0.11), so we must NOT use a set/$var here — a static
|
||||
# proxy_pass resolves via /etc/hosts at config load time and always works.
|
||||
location /api/now-playing/ {
|
||||
rewrite ^/api/now-playing/(.*)$ /$1 break;
|
||||
proxy_pass http://host.docker.internal:8090;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 45s;
|
||||
proxy_connect_timeout 5s;
|
||||
}
|
||||
|
||||
# ── Snapcast JSON-RPC WebSocket ──────────────────────────────────────────
|
||||
location /ws/snapcast {
|
||||
set $snapserver_ws http://snapserver:1780;
|
||||
rewrite ^/ws/snapcast$ /jsonrpc break;
|
||||
proxy_pass $snapserver_ws;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
}
|
||||
|
||||
# ── Gzip ─────────────────────────────────────────────────────────────────
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/javascript application/json;
|
||||
gzip_min_length 1024;
|
||||
}
|
||||
Reference in New Issue
Block a user