{"componentChunkName":"component---src-gatsby-theme-chronoblog-templates-note-js","path":"/notes/nginx-local-setup/","result":{"data":{"mdx":{"parent":{"__typename":"File","fields":{"gitLogLatestDate":"2026-06-20 22:44:21 +0200"}},"id":"fbaea945-50a4-5030-a959-cc2403624bd9","excerpt":"Nginx is a reverse proxy and web server. On a local machine it can sit on port 80 and route traffic to apps running on other ports - a…","frontmatter":{"title":"Nginx local setup","date":"2026-06-21 00:01:00 UTC","job_ad":null,"job_ad_id":null,"job_ad_url":null,"tags":["nginx","devops","wsl"],"cover":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAPoAAAD6AG1e1JrAAABJElEQVQoz5WS6Y6CQBCEef8HNLtIUJRjkUORY2CubzO4UVj9oT3ppHuqu2qO9njDrLWzL2O3/tCFg3cveOErArsmvnP9E/bWCmu1W/N6z5nWmlEoqkJRnCZO+UiRS4beEdoXapbFCR+YMQYhBF3XUlctx4Ng65dsNhlB0NC14CXxQBL3pIkgPnQcDy3xceBcGYxR1KWac1dXlRo5qbvQKCzTCHJyMShp8fb7lq1fsAsvBNsS3y+IonZuHoaO08/ILmwIgoqqtGj9uIoj0AqMvsVGWzwlwShmYAaVA28F83spO+cOk5Ph2jSkaUJdXUmTkTC88P2VE0U9vbvyp5+ipOR8rhGDpMgVWSpI4o4snRg6+/nYrMfk+SM93rRngcfJ7WIUfgHv0Q/r0jUicQAAAABJRU5ErkJggg==","aspectRatio":2.0869565217391304,"src":"/static/26134ab8e250046e63e7926eaadcf73f/c4ecb/cover.png","srcSet":"/static/26134ab8e250046e63e7926eaadcf73f/57ab0/cover.png 192w,\n/static/26134ab8e250046e63e7926eaadcf73f/f4739/cover.png 384w,\n/static/26134ab8e250046e63e7926eaadcf73f/c4ecb/cover.png 768w","srcWebp":"/static/26134ab8e250046e63e7926eaadcf73f/dd090/cover.webp","srcSetWebp":"/static/26134ab8e250046e63e7926eaadcf73f/ae504/cover.webp 192w,\n/static/26134ab8e250046e63e7926eaadcf73f/fef30/cover.webp 384w,\n/static/26134ab8e250046e63e7926eaadcf73f/dd090/cover.webp 768w","sizes":"(max-width: 768px) 100vw, 768px","presentationWidth":768,"presentationHeight":366},"resize":{"src":"/static/26134ab8e250046e63e7926eaadcf73f/c4ecb/cover.png"}}}},"fields":{"slug":"/notes/nginx-local-setup/","readingTime":{"text":"5 min read"}},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Nginx local setup\",\n  \"date\": \"2026-06-21 00:01:00 UTC\",\n  \"cover\": \"./cover.png\",\n  \"tags\": [\"nginx\", \"devops\", \"wsl\"],\n  \"canonical_url\": \"https://sevic.dev/notes/nginx-local-setup/\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Nginx is a reverse proxy and web server. On a local machine it can sit on port 80 and route traffic to apps running on other ports - a frontend on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \":3000\"), \", an API on \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \":4000\"), \", or a Docker Compose stack with published ports.\"), mdx(\"p\", null, \"This post covers install, config layout, reverse proxying, path-based routes, static files, and service commands on a local dev machine. It does not cover HTTPS, production hardening, or multi-domain TLS.\"), mdx(\"p\", null, \"On Windows, use WSL2 with Ubuntu. On macOS or Linux, the same \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"apt\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"brew\"), \" install steps apply.\"), mdx(\"h3\", {\n    \"id\": \"prerequisites\"\n  }, \"Prerequisites\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"WSL2 with Ubuntu (Windows) or a Linux/macOS shell\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"At least one app listening on a local port (for example \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \":3000\"), \")\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"sudo\"), \" access to install packages and edit \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"/etc/nginx\"))), mdx(\"h3\", {\n    \"id\": \"mental-model\"\n  }, \"Mental model\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"server\"), \" - a virtual host block (\", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"listen\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"server_name\"), \") that handles requests for a hostname.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"location\"), \" - a path prefix inside a server (\", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"/\"), \", \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"/api/\"), \") matched against the request URI.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"proxy_pass\"), \" - forwards the request to another HTTP server (your Node app, Compose service, etc.).\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"root\"), \" - serves files from a directory on disk (built SPA, static HTML).\")), mdx(\"p\", null, \"On Debian and Ubuntu, site configs live in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/etc/nginx/sites-available/\"), \" and are enabled with symlinks in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/etc/nginx/sites-enabled/\"), \". The main file \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/etc/nginx/nginx.conf\"), \" includes those enabled sites.\"), mdx(\"h3\", {\n    \"id\": \"install\"\n  }, \"Install\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"sudo apt update\\nsudo apt install nginx\\n\")), mdx(\"p\", null, \"Start Nginx and verify the default page:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"sudo systemctl start nginx\\ncurl -I http://localhost\\n\")), mdx(\"p\", null, \"You should get an HTTP \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"200\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"301\"), \" response.\"), mdx(\"h3\", {\n    \"id\": \"config-layout\"\n  }, \"Config layout\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Path\"), mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Purpose\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"/etc/nginx/nginx.conf\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Main config; includes enabled sites\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"/etc/nginx/sites-available/\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Site config files (one file per app or domain)\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"/etc/nginx/sites-enabled/\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Symlinks to enabled sites\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"/var/log/nginx/access.log\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Request log\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"/var/log/nginx/error.log\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Errors and config issues\")))), mdx(\"p\", null, \"Create a new site file:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"sudo nano /etc/nginx/sites-available/local-dev\\n\")), mdx(\"p\", null, \"Enable it and disable the default site if it conflicts on port 80:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"sudo ln -s /etc/nginx/sites-available/local-dev /etc/nginx/sites-enabled/\\nsudo rm /etc/nginx/sites-enabled/default\\nsudo nginx -t && sudo systemctl reload nginx\\n\")), mdx(\"p\", null, \"Always run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nginx -t\"), \" before reloading. A syntax error blocks reload and leaves the old config in place.\"), mdx(\"h3\", {\n    \"id\": \"proxy-one-service\"\n  }, \"Proxy one service\"), mdx(\"p\", null, \"Forward all traffic to an app on port 3000:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-nginx\"\n  }), \"server {\\n    listen 80;\\n    server_name localhost;\\n\\n    location / {\\n        proxy_pass http://127.0.0.1:3000;\\n        proxy_http_version 1.1;\\n        proxy_set_header Host $host;\\n        proxy_set_header X-Real-IP $remote_addr;\\n        proxy_set_header Upgrade $http_upgrade;\\n        proxy_set_header Connection \\\"upgrade\\\";\\n    }\\n}\\n\")), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Upgrade\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Connection\"), \" headers allow WebSocket connections through the proxy (useful for Vite, Next.js dev server, etc.).\"), mdx(\"p\", null, \"Use an \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"upstream\"), \" block when several backend servers share the same target name; for a single local app, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy_pass\"), \" with a URL is enough.\"), mdx(\"h3\", {\n    \"id\": \"path-based-routes\"\n  }, \"Path-based routes\"), mdx(\"p\", null, \"Route \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/api/\"), \" to a backend on port 4000 and everything else to a frontend on port 3000:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-nginx\"\n  }), \"server {\\n    listen 80;\\n    server_name localhost;\\n\\n    location /api/ {\\n        proxy_pass http://127.0.0.1:4000/;\\n        proxy_set_header Host $host;\\n    }\\n\\n    location / {\\n        proxy_pass http://127.0.0.1:3000;\\n        proxy_set_header Host $host;\\n    }\\n}\\n\")), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Trailing slash in \", mdx(\"inlineCode\", {\n    parentName: \"strong\"\n  }, \"proxy_pass\")), \" - \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy_pass http://127.0.0.1:4000/;\"), \" (note the slash after the port) strips the matched \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/api/\"), \" prefix before forwarding. A request to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/api/health\"), \" reaches the backend as \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/health\"), \". Without the trailing slash, the backend receives \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/api/health\"), \".\"), mdx(\"p\", null, \"Longer prefixes should use more specific \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"location\"), \" blocks. Nginx picks the best match for the request URI.\"), mdx(\"h3\", {\n    \"id\": \"static-files\"\n  }, \"Static files\"), mdx(\"p\", null, \"Serve a built frontend from disk instead of proxying:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-nginx\"\n  }), \"server {\\n    listen 80;\\n    server_name localhost;\\n    root /var/www/my-app;\\n    index index.html;\\n\\n    location / {\\n        try_files $uri $uri/ /index.html;\\n    }\\n}\\n\")), mdx(\"p\", null, mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"try_files\"), \" falls back to \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"index.html\"), \" for client-side routes in SPAs.\"), mdx(\"h3\", {\n    \"id\": \"commands\"\n  }, \"Commands\"), mdx(\"table\", null, mdx(\"thead\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"thead\"\n  }, mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Command\"), mdx(\"th\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Purpose\"))), mdx(\"tbody\", {\n    parentName: \"table\"\n  }, mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo systemctl start nginx\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Start Nginx\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo systemctl stop nginx\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Stop Nginx\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo systemctl restart nginx\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Full restart (drops active connections)\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo systemctl reload nginx\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Reload config without dropping connections\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo systemctl status nginx\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Check service state\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo nginx -t\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Validate config syntax\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"sudo nginx -s reload\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Reload without systemd\")), mdx(\"tr\", {\n    parentName: \"tbody\"\n  }, mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), mdx(\"inlineCode\", {\n    parentName: \"td\"\n  }, \"curl -I http://localhost\")), mdx(\"td\", _extends({\n    parentName: \"tr\"\n  }, {\n    \"align\": null\n  }), \"Smoke test from the shell\")))), mdx(\"p\", null, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"Safe edit workflow:\"), \" edit config \\u2192 \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sudo nginx -t\"), \" \\u2192 \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"sudo systemctl reload nginx\"), \".\"), mdx(\"p\", null, \"Use \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"reload\"), \" after config changes when the syntax test passes. Use \", mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"restart\"), \" when Nginx fails to start or after package upgrades.\"), mdx(\"h3\", {\n    \"id\": \"local-networking-on-windows--wsl\"\n  }, \"Local networking on Windows + WSL\"), mdx(\"p\", null, \"Nginx runs inside WSL. \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"127.0.0.1\"), \" inside WSL refers to the Linux VM, not processes on the Windows host.\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"App runs inside WSL or Docker Compose\"), \" - use \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"http://127.0.0.1:<port>\"), \" in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy_pass\"), \" when the port is published to the WSL host (Compose \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"ports:\"), \" mapping works).\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"p\", {\n    parentName: \"li\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"App runs on Windows only\"), \" - use the Windows host IP from WSL:\"), mdx(\"pre\", {\n    parentName: \"li\"\n  }, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"grep nameserver /etc/resolv.conf | awk '{ print $2 }'\\n\")), mdx(\"p\", {\n    parentName: \"li\"\n  }, \"Put that IP in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"proxy_pass\"), \" instead of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"127.0.0.1\"), \", or run the app inside WSL/Compose so localhost routing stays simple.\"))), mdx(\"p\", null, \"From a Windows browser, \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"http://localhost\"), \" reaches Nginx in WSL when it listens on port 80.\"), mdx(\"h3\", {\n    \"id\": \"troubleshooting\"\n  }, \"Troubleshooting\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Port 80 already in use\"), \" - check what holds the port: \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"sudo ss -tlnp | grep :80\"), \". Stop the conflicting service or change Nginx \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"listen\"), \" to another port (for example \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"8080\"), \").\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"502 Bad Gateway\"), \" - the upstream app is not running or the \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"proxy_pass\"), \" URL is wrong. Confirm the app responds: \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"curl http://127.0.0.1:3000\"), \".\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Config test fails\"), \" - read the path and line from \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"sudo nginx -t\"), \" output; fix the file and test again before reload.\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"strong\", {\n    parentName: \"li\"\n  }, \"Unexpected routing\"), \" - check \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"/var/log/nginx/error.log\"), \" and \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"/var/log/nginx/access.log\"), \".\")), mdx(\"h3\", {\n    \"id\": \"related-posts\"\n  }, \"Related posts\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"a\", _extends({\n    parentName: \"li\"\n  }, {\n    \"href\": \"https://sevic.dev/notes/docker-compose-overview/\"\n  }), \"Docker Compose overview\"), \" - run frontend and API in Compose, then point Nginx at the published host ports\")), mdx(\"h3\", {\n    \"id\": \"demo\"\n  }, \"Demo\"), mdx(\"p\", null, \"Runnable configs for this post live in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nginx-local-setup-demo\"), \" folder. Get access via \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://sevic.dev/demos\"\n  }), \"code demos\"), \".\"));\n}\n;\nMDXContent.isMDXComponent = true;"}},"pageContext":{"id":"fbaea945-50a4-5030-a959-cc2403624bd9"}},"staticQueryHashes":["1961101537","2542493696"]}