We at Beyond Code are dogfeeding ourselves with our own open source projects and software products. Expose is no different. We used ngrok via
valet share or in Homestead heavily but we were missing some features and didn't like the design of their dashboard. We took on the challenge to create an open source alternative written in PHP and released Expose in June 2020.
Expose creates a tunnel from the internet to your local environment and gives you a public URL that anyone can use to access an application on your machine. It works through any Firewall and VPN and is much simpler than setting up individual rules in your Firewall, forwarding traffic on specific ports to your machine and mapping this to URLs.
The Expose project got a lot of traction in the first year and more than 7,000 developers created an account with us to use our free test server. Expose 2 launched in June 2021 and added more features and a new design to Expose – you can host your own Expose server or create an account at expose.dev to use the new features.
Working with webhooks
A webhook is a callback from a 3rd party service to your application. It mostly happens if a state in the 3rd party application changes – for example if a payment gets collected asynchroniously or a long-running task finishes and sends the results to your app. During the setup process, you configure the callback URL to your app in the 3rd party service and set it to something like
your-app.tld/webhooks. When the state changes, your app gets a payload and can handle it according to your needs.
The problem is that the 3rd party service can't send a payload to your local application easily and many people end up deploying minor changes to a server to test the webhook or debug the call on the server directly. The next problem is that you have to trigger the webhook of the 3rd party service to get data and see if you code works. Most of the time, this happens by placing multiple orders in an ecommerce context or invoking whatever needs to happen to receive the callback – all that takes time and there is a better way.
Get Expose and share your local application:
expose share my-local-app.test
This gives you a public URL like https://ke8gbapw.sharedwithexpose.com and you can use this to configure the webhook endpoint in the 3rd party system. Once you receive the first webhook, you can inspect the data in the dashboard that Expose serves on
127.0.0.1:4040 and replay the request locally until you've implemented and tested the feature. No need to trigger the webhook and place dozens of orders or doing micro deployments after every change.
Sharing local sites
Another standard scenario is sharing a local application with someone on your team to get feedback. We are using Slack and most of our communication is async. In situations where we don't want to hop on a video call with screensharing or where it makes more sense that a colleague can click through the app themseves, we use public URLs to share the current state of the app with others.
This process is much faster than pushing a feature branch and wait that someone else can check out the branch, run migrations, build all assets and try the change on their machine. It's much faster than deploying the change to a server and send this link to your team – it's a simple command and it works.
Our Expose setup
You can run the same setup by hosting your own Expose server or create an Expose account and upgrade to the Pro or Business plans. We obviously use our own product and the global network of Expose servers.
Our opinion is that it is easier to use convention over configuration. This is how we've set up our own Expose account. When working with webhooks, we configure one URL for every 3rd party service. This URL follows a specific scheme (yes, we actually own and use this domain):
third-party-service-and-project.our-custom-domain.tld # Paddle for the Expose platform paddle-expose.share.idontcare.lol # Github webhook to update the Expose documentation github-expose.share.idontcare.lol
When we share local applications with other people on our team, we use another convention:
name.our-custom-domain.tld diana.share.idontcare.lol seb.share.idontcare.lol marcel.share.idontcare.lol
This convention allows us to include these URLs in the configuration of our local applications, even if these applications serve content specifically per domain but also prevent us from conflicts where someone else blocks a tunnel on the Expose network. The Beyond Code platform serves our main beyondco.de website but also the websites for our video courses like phppackagedevelopment.com. A middleware decides where the visitor is and serves the correct content.