Shopify app dev and tunnel problem

Rails 8, Ngrok tunnels. Embedded app deployed to Shopify and validated as working by running the bin/dev, or foreman start command with the Procfile.dev file. The setup works perfect on MacOS, but the same setup fails using Linux. Some difference in the CLI???

  • app starts, rails server
  • JS compiles, assets are ready
  • ngrok tunnel starts, no issues
  • login to Shopify store with App, navigate to App

All that is perfect. However, if I use the CLI app dev command with the --tunnel-url set to the ngrok address, it fails because the Linux process and Puma have some problem with the assigned port.

GraphiQL server started on port 3457
Proxy server started on port 3100
10:31:33 web.1    | started with pid 48758
10:31:33 js.1     | started with pid 48759
10:31:33 tunnel.1 | started with pid 48761
10:31:33 js.1     | $ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets --watch
10:31:33 js.1     | [watch] build finished, watching for changes...
Draft updated successfully for extension: old-school
Draft updated successfully for extension: admin-link-extension
10:31:34 web.1    | => Booting Puma
10:31:34 web.1    | => Rails 8.0.2 application starting in development
10:31:34 web.1    | => Run `bin/rails server --help` for more startup options
10:31:34 web.1    | Puma starting in single mode...
10:31:34 web.1    | * Puma version: 6.6.0 ("Return to Forever")
10:31:34 web.1    | * Ruby version: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +YJIT +PRISM [x86_64-linux]
10:31:34 web.1    | *  Min threads: 3
10:31:34 web.1    | *  Max threads: 3
10:31:34 web.1    | *  Environment: development
10:31:34 web.1    | *          PID: 48758
10:31:34 web.1    | Exiting
10:31:34 web.1    | /home/elmer/.rbenv/versions/3.4.2/lib/ruby/gems/3.4.0/gems/puma-6.6.0/lib/puma/binder.rb:342:in 'TCPServer#initialize': Address already in use - bind(2) for "127.0.0.1" port 3100 (Errno::EADDRINUSE)

So this is something where I am hoping against all hopes that someone using the CLI and Rails and the Puma Dev system can help me to pinpoint why the CLI tunnel option is failing.

Hi – I take it the tunnel URL ends in 3100? This is used to launch a small proxy server during development to redirect requests under /.extensions to a handler specifically for those (where the log mentions “Proxy server started…”). The tunnel should point to this which is why its provided via the --tunnel-url flag.

From reading this it looks like Puma’s trying to run on the same port as the proxy. It’d need to be a different one. You could change the port you want Puma to use (however you’ve configured it), or, change the tunnel URL flag.

I was surprised about the mismatch in behaviour, but I’m told on Mac we have an outstanding issue as this doesn’t fail loudly, but the proxy does misbehave.

I am not following the concept here of the /.extensions but anyway.

I am just saying that when I use MacOS, the CLI does seem to behave without issue, but it fails on my Linux box, so I would like to know what to try to expose where the issue is, so it can be resolved. A verbose output from the CLI might help, but I do not see help in there. The process does on the Puma server aspect and we’re toasted, bugsnag gets nothing interesting.

Hi Bill, hope to add some clarification with this:

  • You have Puma configured to run on port 3100
  • When you tell the CLI to use a custom tunnel with --tunnel-url you pass a url and a port there, like: https://ngrok.something.com:<port> (currently setting it also to 3100)

These ports need to be different. Ngrok needs to be running in a different port than Puma, (it could be 3101 for instance).

This is because the CLI creates a small proxy server, so it’s taking control of that port and then Puma fails.

This doesn’t happen on mac because of a bug, Puma takes control of the port in that case and the local proxy doesn’t work. And coincidentally that’s ok as long as you don’t have extensions in your app.

I’ll create an internal issue to address this and add a check to the CLI to validate that the local proxy and the app port are different, and raise a proper error if it happens.

So, as a summary:

  • The linux behaviour is actually more correct
  • To fix it, just run ngrok in a different port than Puma
  • We are going to improve the error message for this.

I start a tunnel to port https://build-april6.ngrok.io:3100 and that is in my Procfile and my package.json, so my tunnel from Shopify to my localhost works perfect.
Now you’re saying I should purposely boot Rails server with a port like 3101 and this will ensure I am goodly? I am not seeing how that works, but OK… will try.

Anything going through the working tunnel on port 3100 hits my localhost. If Puma is not listening to 3100 (ngrok) then what is it getting? Nothing.

So I am not following your advice. Something smells off here. Only this fake tunnel created in the CLI bombs out!! Why??? What is the solution!!

Booting Rails as PORT 3101 allows the CLI to finish booting, but then the tunnel no longer works and the CLI connection dies, and loads up as an AggregateError… till I shut down.

So now I am confused. There has to be a way to get the CLI to work nicely with tunnels.

Some thing are very unclear here, so maybe I will write that out here for all.

  • everything works (AFAIK) without the CLI. My App, tunnel to it on localhost at a port, and Shopify all work and communicate. I can safely setup webhooks, admin proxy calls, and direct fetch. Great! Rails boots up at the port designated as my tunnel, and we’re cooking!

If I start with the CLI dev command, pointing at this same tunnel, expecting Shopify to work, all things with Linux bust. Why? The CLI boots a server on that port? I expected the CLI dev command to use this tunnel as a match for the one in the App itself, but the explanation I now am hearing, is that this tunnel URL is not in fact to match? OK. So how does it work? I have only ONE NAMED tunnel. foo.ngrok.io on port 3100. That competes with my existing working App?

We cannot have two tunnels. So how does one tunnel work? Any clarity on this would be great! I have always booted my localhost App up on the same port as my named tunnel, my Apps point at that named tunnel, and I am good to go. The CLI seems to clash with this. So how to replace my App running on a named tunnel for the CLI version? There has to be some kind of simple explanation!!

Solved by being more careful. Procfile tunnel:port and package.json tunnel-url are same. Great! Now set the port of the App to be different and it all works fine. Set the port in the web.toml to match that App server, and the CLI does the rest, without trouble, including extensions.

1 Like