Using Sites Secured by Laravel Herd with Expo
We have been subscribers of Laravel Herd since day 1. In fact, we were there in Nashville at Laracon in 2023) and witnessed the announcement live! We immediately recognized the value of a GUI for Laravel Valet, with a few extra goodies sprinkled on top.
One of the suggestions I made to Taylor immediately following the announcements was "It would be amazing if it could support NVM." Since it handles switching PHP version like breeze, I figured it would be the perfect setup for our team as avid users of NVM (and Node.JS). Safe to say, I was tired of brewing our PHP setups on macOS.
One nice thing Laravel Herd and Laravel Valet do behind the scenes is install the LaravelValetCASelfSigned.pem
into the macOS Keychain, thus trusting all certificates signed with Valet's CA for any secured sites. When this featured was introduced, it allowed Developers to simply issue a certificate to setup a HTTPS connection for their local dev site without needing to type in their password. Previously, you would have to authenticate the action in the Keychain to trust each site individually. After doing this many times, it can get a little annoying to type in your password each time.
One of the painpoints we experienced early on when pairing our mobile apps (Expo, Swift, Kotlin, etc.) with a Laravel backend was invalid HTTPS certificates. Since iOS Simulators and Android emulators do not leverage the macOS Keychain, read on below to see how to setup your test devices to trust your Herd or Valet sites.
iOS Simulator
This is very easy to do on iOS simulators. First, make sure your favorite simulator is open and fully booted.
Next, locate your CA Certificate at one of the following locations:
- Herd -
~/Library/Application Support/Herd/config/valet/CA/LaravelValetCASelfSigned.pem
- Valet -
~/.config/valet/CA/LaravelValetCASelfSigned.pem
Now drag-and-drop that certificate file onto the simulator window. Nothing obvious happens on drop. However, your Herd/Valet CA should now automatically be trusted.
You can verify this by going to Settings > General > About > Scroll to the bottom > Certificate Trust Settings
and you will see a toggle switch enabled for the Laravel Valet CA Self Signed CN
.
This is the name of the certificate file for both Herd and Valet, as Herd is actually implements a GUI around slightly modified version (fork) of Larvel Valet.
One thing to note is anytime you download any new iOS SDKs or launch new simulator devices, you will need to repeat the above steps. This also includes the scenario when you "Erase All Content and Settings" for your sim.
Android Emulator for Native Apps
In Android land, it's a little more complicated to install Laravel Valet CA at the system level. Instead, we are just going to ship the CA with the app bundle when it's installed. The following instructions should work for any type of Android app, but we also show how to automate the process on Expo apps by creating a project plugin.
If you are using Expo, you should skip this section and go to the next section.
First, we are going to create a Network Security Configuration file at app/src/main/res/xml/network_security_config.xml
with the following contents:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="@raw/valet" />
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
This config file essentially tells your app to trust the Laravel Valet cert in addition to the Android OS CAs. You can read more about this file here.
Next, we need to copy this CA file into our App bundle. Since we don't want to blindly copy the CA from our individual system into the repo, we can copy the CA at build time instead. This solution is a little more portable across team members.
As a reminder, locate your CA Certificate at one of the following locations:
- Herd -
~/Library/Application Support/Herd/config/valet/CA/LaravelValetCASelfSigned.pem
- Valet -
~/.config/valet/CA/LaravelValetCASelfSigned.pem
In your app's build.gradle
, define the following:
android {
// Your existing android configuration
}
def sourceFile = "${System.properties['user.home']}/Library/Application Support/Herd/config/valet/CA/LaravelValetCASelfSigned.pem"
def targetDir = "${projectDir}/src/main/res/raw"
tasks.register("copyToRaw", Copy) {
from(sourceFile)
into(targetDir)
rename { fileName ->
"valet" // must be lowercase, no special chars
}
}
// Make sure it runs before you build the APK
preBuild.dependsOn(copyToRaw)
One caveat to this solution is your entire team should be using Herd vs. Valet. It might be a little weird to mix and match, but you could easily solve it with a symlink (an exercise left for the reader). You will also likely need to add raw/valet
to your .gitignore
, as this will be unique per team member.
Now register your network security configuration in your AndroidManifest.xml
file.
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:networkSecurityConfig="@xml/network_security_config">
<!-- The rest of your manifest -->
</application>
</manifest>
Finally, be sure to setup the emulator's DNS as noted below.
Android Emulator for Native Apps
In Android land, it's a little more complicated to install Laravel Valet CA at the system level. Instead, we are just going to ship the CA with the app bundle when it's installed. The following instructions should work for any type of Android app, but we also show how to automate the process on Expo apps by creating a project plugin.
If you are using Expo, you should skip this section and go to the next section.
First, we are going to create a Network Security Configuration file at app/src/main/res/xml/network_security_config.xml
with the following contents:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="@raw/valet" />
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
This config file essentially tells your app to trust the Laravel Valet cert in addition to the Android OS CAs. You can read more about this file here.
Next, we need to copy this CA file into our App bundle. Since we don't want to blindly copy the CA from our individual system into the repo, we can copy the CA at build time instead. This solution is a little more portable across team members.
As a reminder, locate your CA Certificate at one of the following locations:
- Herd -
~/Library/Application Support/Herd/config/valet/CA/LaravelValetCASelfSigned.pem
- Valet -
~/.config/valet/CA/LaravelValetCASelfSigned.pem
In your app's build.gradle
, define the following:
android {
// Your existing android configuration
}
def sourceFile = "${System.properties['user.home']}/Library/Application Support/Herd/config/valet/CA/LaravelValetCASelfSigned.pem"
def targetDir = "${projectDir}/src/main/res/raw"
tasks.register("copyToRaw", Copy) {
from(sourceFile)
into(targetDir)
rename { fileName ->
"valet" // must be lowercase, no special chars
}
}
// Make sure it runs before you build the APK
preBuild.dependsOn(copyToRaw)
One caveat to this solution is your entire team should be using Herd vs. Valet. It might be a little weird to mix and match, but you could easily solve it with a symlink (an exercise left for the reader). You will also likely need to add raw/valet
to your .gitignore
, as this will be unique per team member.
Now register your network security configuration in your AndroidManifest.xml
file.
<?xml version='1.0' encoding='utf-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:networkSecurityConfig="@xml/network_security_config">
<!-- The rest of your manifest -->
</application>
</manifest>
Finally, be sure to setup the emulator's DNS as noted below.
DNS Settings for Android Emulators
One last thing to note: you will likely need to configure your Emaultor's AndroidWifi network to be pointed at a custom DNS server that will resolve all *.test
domains to your emulators loopback interface IP 10.0.2.2
. In other words, we need to make sure the app is reaching Laravel Herd. This will automatically forward requests to your Mac's localhost
. We have a DNS server specifically for our Android emulators avalable to our team via Tailscale.
We have over a decade of experience building and shipping mobile applications with all types of technologies, ranging from Swift/Objective-C & Kotlin/Jave all the way to Expo & React Native.
If you’d like help implementing these features or help with your mobile, reach out to our team today to get the support you need.