Skip to main content
In this guide you’ll find a focused workflow to resolve a common Backstage development issue: the frontend and backend are configured to use localhost, which prevents accessing Backstage from an external browser using the server’s IP or DNS. This article preserves the original configuration examples and shows the minimal changes required to make Backstage reachable externally while keeping local overrides manageable. What you’ll learn
  • Why localhost bindings block external access
  • Which config keys to update (app.baseUrl, backend.baseUrl, backend.listen, backend.cors.origin)
  • How to apply changes safely with app-config.local.yaml
  • How to restart and verify the dev server
Problem overview
  • The frontend is configured with app.baseUrl: http://localhost:3000. Generated URLs and the webpack dev server advertise localhost, so requests sent to the server’s external IP are rejected by the host checks or by the server binding.
  • The backend uses localhost for baseUrl and may bind to the loopback interface, or its CORS config may not allow the external frontend origin, causing the browser to block API calls.
  • Solution: switch the frontend app.baseUrl and backend baseUrl to the server IP or DNS name, ensure the backend listens on an interface that accepts external requests (commonly 0.0.0.0), and add the frontend origin to backend.cors.origin.
Example shortened console output showing the dev server running locally:
You may see the browser show a connection refused error when navigating to the server IP on port 3000 (because app.baseUrl is localhost):
A Chrome browser window displaying a "This site can't be reached" error (147.182.170.10 refused to connect, ERR_CONNECTION_REFUSED) with a reload button and troubleshooting suggestions. The address bar and several tabs are visible at the top and a teal mouse cursor is near the bottom right.
Initial (problematic) app-config snippet
Fix: update the shared app-config to use the server IP or DNS Follow these steps to allow external browser access and correct frontend↔backend communication:
  1. Set app.baseUrl to the server IP or DNS with port 3000.
  2. Set backend.baseUrl to the same server IP or DNS with port 7007.
  3. Configure the backend listen.host to 0.0.0.0 (or remove host to bind all interfaces) so it accepts external connections.
  4. Add the frontend origin to backend.cors.origin so the browser is allowed to call the backend.
Example updated app-config.yaml for this demo (replace 147.182.170.10 with your server IP or DNS name):
Configuration quick reference Note: If you have a DNS name for your server, prefer that instead of a raw IP address for better maintainability and SSL/HTTPS compatibility. Restart the dev server After changing configuration files you must restart Backstage to load the new settings. Steps:
  1. Stop the running dev server (Ctrl+C in the terminal; press again if necessary to force exit).
  2. Start it again:
You should see the backend and frontend log successful startup and listening on the configured addresses. After restarting, the frontend should be reachable at http://147.182.170.10:3000 and be able to communicate with the backend at http://147.182.170.10:7007. Using app-config.local.yaml for local overrides
  • Prefer placing machine-specific or development-only overrides in app-config.local.yaml so the shared app-config.yaml remains suitable across environments.
  • Backstage merges configuration files; app-config.local.yaml (if present during development) overrides keys in app-config.yaml.
Example app-config.local.yaml with minimal overrides:
Restore the shared app-config.yaml to scaffold defaults for portability:
Because app-config.local.yaml has precedence in development, the effective configuration used by yarn dev is the merge of app-config.yaml and the local overrides. After creating or modifying app-config.local.yaml, restart the dev server.
Use app-config.local.yaml for developer- or machine-specific settings (like using an external IP for a demo server). Keep app-config.yaml for defaults shared among environments, and use production-specific files (e.g., app-config.production.yaml) when deploying to production.
Security reminder
Exposing a development server on a public IP can expose sensitive endpoints or secrets. Avoid using production secrets in development configs and secure access with firewall rules or VPNs when demoing externally.
Troubleshooting checklist
  • Confirm the server firewall/security group allows ports 3000 and 7007.
  • Verify Backstage logs show the backend listening on 0.0.0.0:7007 (or expected host/port).
  • Inspect browser DevTools Console and Network tab for CORS errors; adjust backend.cors.origin as needed.
  • If the frontend still advertises localhost, clear caches and ensure yarn dev restarted after config changes.
Summary
  • The frontend refused external connections because app.baseUrl was set to localhost. The backend may also have been bound only to localhost or rejected cross-origin requests.
  • Update app.baseUrl, backend.baseUrl, and backend.cors.origin to the server IP or DNS name and ensure the backend binds to an interface that accepts external connections.
  • Prefer app-config.local.yaml for local overrides to keep shared configuration environment-agnostic.
  • Always restart Backstage after modifying configuration and double-check firewall and CORS settings.
References and further reading

Watch Video