You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<p>Two containers share an internal Docker bridge network:</p>
26
26
<ul>
27
-
<li><strong><code>backend</code></strong>— Node.js app in API-only mode (<code>SERVE_UI=false</code>, <code>FRONTEND_ONLY_API=true</code>). Publishes port 3000 for external webhook ingress.</li>
28
-
<li><strong><code>frontend</code></strong>— nginx serving the static UI and proxying admin API requests to the backend over the internal network. No published port for the backend API means direct external access to <code>/api/*</code> is blocked at the network level.</li>
27
+
<li><strong><code>backend</code></strong> Node.js app in API-only mode (<code>SERVE_UI=false</code>, <code>FRONTEND_ONLY_API=true</code>). Publishes port 3000 for external webhook ingress.</li>
28
+
<li><strong><code>frontend</code></strong> nginx serving the static UI and proxying admin API requests to the backend over the internal network. No published port for the backend API means direct external access to <code>/api/*</code> is blocked at the network level.</li>
<li><code>docker-compose.yml</code>— service definitions</li>
40
-
<li><code>deploy/docker/nginx.conf</code>— nginx config for the frontend container</li>
41
-
<li><code>.dockerignore</code>— excludes <code>.env.*</code> files, the database, and other unnecessary paths from the build context so secrets are not baked into the image</li>
<li><code>docker-compose.yml</code> service definitions</li>
40
+
<li><code>deploy/docker/nginx.conf</code> nginx config for the frontend container</li>
41
+
<li><code>.dockerignore</code> excludes <code>.env.*</code> files, the database, and other unnecessary paths from the build context so secrets are not baked into the image</li>
42
42
</ul>
43
43
<p>All are included in the repo under their respective paths.</p>
44
-
<h2id="step-1--build-the-ui-css">Step 1 — Build The UI CSS</h2>
44
+
<h2id="step-1-build-the-ui-css">Step 1) Build The UI CSS</h2>
45
45
<p>The frontend container serves static files. Build the CSS before starting the stack:</p>
46
46
<pre><codeclass="language-bash">npm install
47
47
npm run build:css
48
48
</code></pre>
49
49
<p>This outputs <code>ui/dist/styles.css</code>, which the nginx container will serve directly.</p>
50
-
<h2id="step-2--configure-the-nginx-auth-snippet">Step 2 — Configure The nginx Auth Snippet</h2>
50
+
<h2id="step-2-configure-the-nginx-auth-snippet">Step 2) Configure The nginx Auth Snippet</h2>
51
51
<p>The frontend nginx config includes an auth snippet at <code>/etc/nginx/snippets/gateherald-admin-auth.conf</code>, mounted from <code>deploy/nginx/snippets/</code>. Choose one:</p>
<p>The <code>docker-compose.yml</code> mounts this file into the frontend container at <code>/etc/nginx/.htpasswd-gateherald</code>.</p>
62
-
<h2id="step-3--set-the-shared-secret">Step 3 — Set The Shared Secret</h2>
62
+
<h2id="step-3-set-the-shared-secret">Step 3) Set The Shared Secret</h2>
63
63
<p><code>ADMIN_PROXY_SHARED_SECRET</code> is the shared credential between the nginx frontend and the Node backend. The frontend injects it as a request header; the backend verifies it before accepting any admin API call.</p>
<p>Set <code>ADMIN_PROXY_SHARED_SECRET</code> to this value in your <code>.env.production</code> file (see Step 4). That is the only place it needs to go.</p>
68
-
<p><code>deploy/docker/nginx.conf</code> uses <code>${ADMIN_PROXY_SHARED_SECRET}</code> as a placeholder. At startup, the nginx container reads the value from the environment and substitutes it before the config is loaded — the secret is never written into any file in the repository.</p>
68
+
<p><code>deploy/docker/nginx.conf</code> uses <code>${ADMIN_PROXY_SHARED_SECRET}</code> as a placeholder. At startup, the nginx container reads the value from the environment and substitutes it before the config is loaded; the secret is never written into any file in the repository.</p>
69
69
<p>The frontend nginx container only receives <code>ADMIN_PROXY_SHARED_SECRET</code> from the environment. Other backend secrets (<code>DB_PASSWORD</code>, <code>API_TOKEN</code>, etc.) are passed only to the backend service via <code>env_file: .env.production</code> and are not exposed to the nginx container.</p>
<p>Set <code>ALLOWED_ORIGINS</code> to the external URL where the frontend nginx is reachable. This controls CORS for browser-initiated API requests.</p>
80
80
<p>For SQLite the default database location is used; it will be persisted via the named volume defined in <code>docker-compose.yml</code>. If using Postgres or MySQL instead, add the <code>DATABASE_URL</code> / <code>DB_*</code> vars from <code>.env.production.example</code>.</p>
81
-
<h2id="step-5--run-migrations">Step 5 — Run Migrations</h2>
81
+
<h2id="step-5-run-migrations">Step 5) Run Migrations</h2>
82
82
<p>Run database migrations once before starting the app for the first time, or after any upgrade that includes new migrations:</p>
83
83
<pre><codeclass="language-bash">docker compose run --rm backend node scripts/db-migrate.js
84
84
</code></pre>
85
-
<h2id="step-6--start-the-stack">Step 6 — Start The Stack</h2>
85
+
<h2id="step-6-start-the-stack">Step 6) Start The Stack</h2>
86
86
<pre><codeclass="language-bash">docker compose up -d
<p>The <code>docker-compose.yml</code> exposes the frontend on HTTP port 8080. For HTTPS, put a TLS-terminating reverse proxy (another nginx, Caddy, Traefik, etc.) in front of port 8080 and set the appropriate <code>X-Forwarded-Proto</code> header. The app already reads this header for cookie <code>Secure</code> flag decisions.</p>
97
-
<p>Do not expose the backend container's port 3000 through TLS termination intended for admin users — keep that path for webhook ingress only.</p>
<p>By default the backend uses SQLite, persisted via a named Docker volume. This is sufficient for a single-node deployment. If you want a proper relational database with concurrent write support and a fully independent data lifecycle, add a <code>db</code> service to the Compose stack.</p>
100
-
<h3id="1--install-the-driver">1 — Install The Driver</h3>
100
+
<h3id="1-install-the-driver">1) Install The Driver</h3>
101
101
<p>The Postgres or MySQL driver must be present in the image. Add it as a production dependency before building:</p>
102
102
<pre><codeclass="language-bash"># Postgres
103
103
npm install pg pg-hstore
104
104
105
105
# MySQL
106
106
npm install mysql2
107
107
</code></pre>
108
-
<h3id="2--add-the-db-service-to-docker-composeyml">2 — Add The db Service To docker-compose.yml</h3>
108
+
<h3id="2-add-the-db-service-to-docker-composeyml">2) Add The db Service To docker-compose.yml</h3>
109
109
<p>Add a <code>db</code> service on the same internal network, with its own named volume. Update <code>backend</code> to depend on it:</p>
110
110
<pre><codeclass="language-yaml">volumes:
111
-
gateherald-data: # remove or repurpose — no longer used for SQLite
111
+
gateherald-data: # remove or repurpose; no longer used for SQLite
112
112
gateherald-db: # postgres data directory
113
113
114
114
services:
@@ -123,7 +123,7 @@ <h3 id="2--add-the-db-service-to-docker-composeyml">2 — Add The db Service To
123
123
volumes:
124
124
- gateherald-db:/var/lib/postgresql/data
125
125
restart: unless-stopped
126
-
# No 'ports' — not reachable from outside Docker
126
+
# No 'ports' - not reachable from outside Docker
127
127
128
128
backend:
129
129
build: .
@@ -137,7 +137,7 @@ <h3 id="2--add-the-db-service-to-docker-composeyml">2 — Add The db Service To
137
137
restart: unless-stopped
138
138
</code></pre>
139
139
<p>Do not publish the <code>db</code> container's port. It only needs to be reachable from <code>backend</code> on the internal network.</p>
<p><code>DB_HOST=db</code> resolves to the <code>db</code> container via Docker's internal DNS. <code>DB_SSL=false</code> is appropriate here because the connection stays on the internal bridge network; enable it if your setup routes through a TLS-capable proxy.</p>
151
-
<h3id="4--run-migrations">4 — Run Migrations</h3>
151
+
<h3id="4-run-migrations">4) Run Migrations</h3>
152
152
<p>Wait for Postgres to be ready before migrating. A simple one-off approach:</p>
153
153
<pre><codeclass="language-bash">docker compose up -d db
154
154
# wait a few seconds for Postgres to initialise, then:
0 commit comments