stacker.news: Unable to run stacker.news locally

Description I wonder if the instructions here are still up to date. I don’t seem to get the outcome that I would expect after running docker-compose up --build.

Steps to Reproduce I followed the first two steps (installed docker-compose and cloned the project from github).

Expected behavior I get these last 3 messages in my console logs. Attaching the full console logs here too. log.txt

app exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
dependency failed to start: container app exited (0)

I would expect the app not to exit so that I can access the site at localhost:3000.

Environment: If you only experience the issue on certain devices or browsers, provide that info.

  • Device: Macbook Pro from 2019 (also tried on an older iMac, with same results).
  • Browser: Chrome

About this issue

  • Original URL
  • State: closed
  • Created 4 months ago
  • Comments: 55 (55 by maintainers)

Most upvoted comments

Mhh, not sure why the CSP would block these requests which are essential for the app to load. Those are the ones using nonces. If your browser doesn’t support CSP nonces, it should fall back to host-based matching, so only inline scripts and scripts from the same domain are allowed:

When such a policy is set, modern browsers will execute only those scripts whose nonce attribute matches the value set in the policy header, as well as scripts dynamically added to the page by scripts with the proper nonce. Older browsers, which don’t support the CSP3 standard, will ignore the nonce-* and ‘strict-dynamic’ keywords and fall back to [script-src ‘unsafe-inline’ https: http:] which will not provide any protection against XSS vulnerabilities, but will allow the application to function properly.

https://csp.withgoogle.com/docs/strict-csp.html

Does CSP also block the requests in Chrome?

You could try to disable the CSP using this patch:

patch
diff --git a/middleware.js b/middleware.js
index 858b80e4..2810b41c 100644
--- a/middleware.js
+++ b/middleware.js
@@ -19,44 +19,44 @@ export function middleware (request) {
     resp = referrerMiddleware(request)
   }
 
-  const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
-  const cspHeader = [
-    // if something is not explicitly allowed, we don't allow it.
-    "default-src 'none'",
-    "font-src 'self' a.stacker.news",
-    // we want to load images from everywhere but we can limit to HTTPS at least
-    "img-src 'self' a.stacker.news m.stacker.news https: data: blob:",
-    "media-src 'self' a.stacker.news m.stacker.news",
-    // Using nonces and strict-dynamic deploys a strict CSP.
-    // see https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html#strict-policy.
-    // Old browsers will ignore nonce and strict-dynamic and fallback to host-based matching and unsafe-inline
-    process.env.NODE_ENV === 'production'
-      ? `script-src 'self' 'unsafe-inline' 'nonce-${nonce}' 'strict-dynamic' https:`
-      // unsafe-eval is required during development due to react-refresh.js
-      // see https://github.com/vercel/next.js/issues/14221
-      : `script-src 'self' 'unsafe-inline' 'unsafe-eval' 'nonce-${nonce}' 'strict-dynamic' https:`,
-    // unsafe-inline for styles is not ideal but okay if script-src is using nonces
-    "style-src 'self' a.stacker.news 'unsafe-inline'",
-    "manifest-src 'self'",
-    'frame-src www.youtube.com platform.twitter.com',
-    "connect-src 'self' https: wss:",
-    // disable dangerous plugins like Flash
-    "object-src 'none'",
-    // blocks injection of <base> tags
-    "base-uri 'none'",
-    // tell user agents to replace HTTP with HTTPS
-    'upgrade-insecure-requests',
-    // prevents any domain from framing the content (defense against clickjacking attacks)
-    "frame-ancestors 'none'"
-  ].join('; ')
-
-  resp.headers.set('Content-Security-Policy', cspHeader)
-  // for browsers that don't support CSP
-  resp.headers.set('X-Frame-Options', 'DENY')
-  // more useful headers
-  resp.headers.set('X-Content-Type-Options', 'nosniff')
-  resp.headers.set('Referrer-Policy', 'origin-when-cross-origin')
-  resp.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
+  // const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
+  // const cspHeader = [
+  //   // if something is not explicitly allowed, we don't allow it.
+  //   "default-src 'none'",
+  //   "font-src 'self' a.stacker.news",
+  //   // we want to load images from everywhere but we can limit to HTTPS at least
+  //   "img-src 'self' a.stacker.news m.stacker.news https: data: blob:",
+  //   "media-src 'self' a.stacker.news m.stacker.news",
+  //   // Using nonces and strict-dynamic deploys a strict CSP.
+  //   // see https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html#strict-policy.
+  //   // Old browsers will ignore nonce and strict-dynamic and fallback to host-based matching and unsafe-inline
+  //   process.env.NODE_ENV === 'production'
+  //     ? `script-src 'self' 'unsafe-inline' 'nonce-${nonce}' 'strict-dynamic' https:`
+  //     // unsafe-eval is required during development due to react-refresh.js
+  //     // see https://github.com/vercel/next.js/issues/14221
+  //     : `script-src 'self' 'unsafe-inline' 'unsafe-eval' 'nonce-${nonce}' 'strict-dynamic' https:`,
+  //   // unsafe-inline for styles is not ideal but okay if script-src is using nonces
+  //   "style-src 'self' a.stacker.news 'unsafe-inline'",
+  //   "manifest-src 'self'",
+  //   'frame-src www.youtube.com platform.twitter.com',
+  //   "connect-src 'self' https: wss:",
+  //   // disable dangerous plugins like Flash
+  //   "object-src 'none'",
+  //   // blocks injection of <base> tags
+  //   "base-uri 'none'",
+  //   // tell user agents to replace HTTP with HTTPS
+  //   'upgrade-insecure-requests',
+  //   // prevents any domain from framing the content (defense against clickjacking attacks)
+  //   "frame-ancestors 'none'"
+  // ].join('; ')
+  //
+  // resp.headers.set('Content-Security-Policy', cspHeader)
+  // // for browsers that don't support CSP
+  // resp.headers.set('X-Frame-Options', 'DENY')
+  // // more useful headers
+  // resp.headers.set('X-Content-Type-Options', 'nosniff')
+  // resp.headers.set('Referrer-Policy', 'origin-when-cross-origin')
+  // resp.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains')
 
   return resp
 }

Copy the content into a file and run git apply <file>.

Does that fix the issue?

I think it’s because docker requires root permissions and then everything that is created inside a container has the owner root on the host machine

Yes, for shared volumes the files that docker creates in the shared volume have root perms on linux (doesn’t happen on windows and mac as the host for docker is actually a vm). The solve here (I think) is to tell docker to run commands unprivileged as a user with the host’s uid and gid … which is what I did in the follow on commits.

For some reason, the build process is creating some directories with root as the owner and group. No idea why but, it happens every time I run sndev start. Sometimes it’s just the .next/ directory, sometimes it’s the node_modules/ directory, sometimes both. I tried chowning it but it always goes back to root.

I think it’s because docker requires root permissions and then everything that is created inside a container has the owner root on the host machine

just an educated guess, not sure

I just pushed a change that might fix it:

-RUN useradd -m -u "$UID" -g "$GID" apprunner
+RUN useradd -om -u "$UID" -g "$GID" apprunner

From useradd -h:

  -o, --non-unique              allow to create users with duplicate
                                (non-unique) UID

I added --verbose to the docker compose command and this is the output:

image

It should be possible I’m looking into it. This might explain why some people have always had a hard time with our docker setup.

ohhhh hmmmmm I can assume and uid on builds maybe

I got error below when I tried to update the bio and again when trying to create a post

That error code 23502 suggests there a uniqueness constraint getting violated. I’m not sure why that would be the case but I’ll let you know if anything comes up.

If you want, checkout this branch: https://github.com/stackernews/stacker.news/tree/localdev

Then run ./sndev start

It has a number of refinements to the docker setup that should make it more reliable and deterministic (in addition to populating db/search with a seed).

One more screenshot. I think this one might be helpful:

Output for docker-compose up app

image

Actually, while I was resolving the issues that i encountered when using the npm run worker approach, it now works when using the docker-compose up --build approach. I’m not sure what did the trick, I suspect it is because of the environment variable for OPENSEARCH, i.e. export OPENSEARCH_NODE which was export OPENSEARCH_URL on my system, but I can run SN locally at http://localhost:3000/. I do get another error at this point, but just thought of updating here before I waste more of your time.

EDIT: My hunch seems confirmed, I had to run export OPENSEARCH_URL=http://localhost:3000 before being able to run the container.