diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 79c07f21d..42ac13eb1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,6 +19,7 @@ jobs:
uses: ./.github/workflows/kotlin.yml
swift:
uses: ./.github/workflows/swift.yml
+ secrets: inherit
static-analysis:
uses: ./.github/workflows/static-analysis.yml
terraform:
diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml
index e4464e5e8..12dd21c61 100644
--- a/.github/workflows/swift.yml
+++ b/.github/workflows/swift.yml
@@ -2,6 +2,10 @@ name: Swift
on:
workflow_call:
+env:
+ # TODO: Change this to "prod" when app is released
+ CLIENT_ENV: staging
+
jobs:
build:
runs-on: macos-13
@@ -37,20 +41,137 @@ jobs:
key: ${{ matrix.target.platform }}-swift-${{ hashFiles('swift/*', 'rust/**/*.rs', 'rust/**/*.toml', 'rust/**/*.lock}') }}
restore-keys: |
${{ matrix.target.platform }}-swift-
- - name: Build app
+ - name: Install the Apple build certificate and provisioning profile
env:
- ONLY_ACTIVE_ARCH: no
+ BUILD_CERT: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }}
+ BUILD_CERT_PASS: ${{ secrets.APPLE_BUILD_CERTIFICATE_P12_PASSWORD }}
+ INSTALLER_CERT: ${{ secrets.APPLE_MAC_INSTALLER_CERTIFICATE_BASE64 }}
+ INSTALLER_CERT_PASS: ${{ secrets.APPLE_MAC_INSTALLER_CERTIFICATE_P12_PASSWORD }}
+ KEYCHAIN_PASS: ${{ secrets.APPLE_RUNNER_KEYCHAIN_PASSWORD }}
+ IOS_APP_PP: ${{ secrets.APPLE_IOS_APP_PROVISIONING_PROFILE }}
+ IOS_NE_PP: ${{ secrets.APPLE_IOS_NE_PROVISIONING_PROFILE }}
+ MACOS_APP_PP: ${{ secrets.APPLE_MACOS_APP_PROVISIONING_PROFILE }}
+ MACOS_NE_PP: ${{ secrets.APPLE_MACOS_NE_PROVISIONING_PROFILE }}
run: |
+ BUILD_CERT_PATH=$RUNNER_TEMP/build_certificate.p12
+ INSTALLER_CERT_PATH=$RUNNER_TEMP/installer_certificate.cer
+
+ KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
+ PP_PATH=~/Library/MobileDevice/Provisioning\ Profiles
+ mkdir -p "$PP_PATH"
+
+ # import certificate and provisioning profiles from secrets
+ echo -n "$BUILD_CERT" | base64 --decode -o $BUILD_CERT_PATH
+
+ # Matrix won't let us access secrets (for good reason), so use an explicit conditional here instead
+ if [ "${{ matrix.target.platform }}" = "iOS" ]; then
+ echo -n "$IOS_APP_PP" | base64 --decode -o "$PP_PATH"/app.mobileprovision
+ echo -n "$IOS_NE_PP" | base64 --decode -o "$PP_PATH"/ne.mobileprovision
+ elif [ "${{ matrix.target.platform }}" = "macOS" ]; then
+ echo -n "$MACOS_APP_PP" | base64 --decode -o "$PP_PATH"/app.provisionprofile
+ echo -n "$MACOS_NE_PP" | base64 --decode -o "$PP_PATH"/ne.provisionprofile
+
+ # Submission to the macOS app store requires an installer package
+ # which must be signed separately.
+ echo -n "$INSTALLER_CERT" | base64 --decode -o $INSTALLER_CERT_PATH
+ else
+ echo "Platform not supported"
+ exit 1
+ fi
+
+ # create temporary keychain
+ security create-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN_PATH
+ security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
+ security unlock-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN_PATH
+
+ # import certificate to keychain
+ security import $BUILD_CERT_PATH -P "$BUILD_CERT_PASS" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+
+ if [ "${{ matrix.target.platform }}" = "macOS" ]; then
+ security import $INSTALLER_CERT_PATH -P "$INSTALLER_CERT_PASS" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
+ fi
+ security list-keychain -d user -s $KEYCHAIN_PATH
+ - name: Build and sign app
+ id: build
+ env:
+ # Build universal binary
+ ONLY_ACTIVE_ARCH: no
+ # Needed because `productbuild` doesn't support picking this up automatically like Xcode does
+ INSTALLER_CODE_SIGN_IDENTITY: "3rd Party Mac Developer Installer: Firezone, Inc. (47R2M6779T)"
+ run: |
+ # Explicitly select Xcode version to use
sudo xcode-select -s /Applications/Xcode_14.3.app
+
+ # Needed by the linter built into the build process
brew install swift-format
- cp Firezone/xcconfig/Developer.xcconfig.ci-${{ matrix.target.platform }} Firezone/xcconfig/Developer.xcconfig
- cp Firezone/xcconfig/Server.xcconfig.ci Firezone/xcconfig/Server.xcconfig
- xcodebuild archive \
- -configuration Release \
- -scheme Firezone \
- -sdk ${{ matrix.target.sdk }} \
- -destination '${{ matrix.target.destination }}' \
- CODE_SIGNING_ALLOWED=no
+
+ # Copy xcconfig templates
+ cp Firezone/xcconfig/Developer.xcconfig.firezone Firezone/xcconfig/Developer.xcconfig
+ cp Firezone/xcconfig/Server.xcconfig.${{ env.CLIENT_ENV }} Firezone/xcconfig/Server.xcconfig
+
+ # App Store Connect requires a new build version on each upload and it must be an integer.
+ # See https://developer.apple.com/documentation/xcode/build-settings-reference#Current-Project-Version
+ seconds_since_epoch=$(date +%s)
+ sed -i '' "s/CURRENT_PROJECT_VERSION = [0-9]/CURRENT_PROJECT_VERSION = $seconds_since_epoch/" \
+ Firezone.xcodeproj/project.pbxproj
+
+ # Unfortunately the macOS app requires an installer package to make it into the App Store,
+ # while iOS requires an ipa. The process for building each of these is slightly different.
+ if [ "${{ matrix.target.platform }}" = "iOS" ]; then
+ # Build archive
+ xcodebuild archive \
+ -archivePath ~/Firezone.xcarchive \
+ -configuration Release \
+ -scheme Firezone \
+ -sdk ${{ matrix.target.sdk }} \
+ -destination '${{ matrix.target.destination }}'
+ # Export IPA
+ xcodebuild \
+ -exportArchive \
+ -archivePath ~/Firezone.xcarchive \
+ -exportPath ~/ \
+ -exportOptionsPlist Firezone/ExportOptions.plist
+
+ # Save resulting file to use for upload
+ echo "app_bundle=~/Firezone.ipa" >> "$GITHUB_OUTPUT"
+ elif [ "${{ matrix.target.platform }}" = "macOS" ]; then
+ # Build app bundle
+ xcodebuild build \
+ -configuration Release \
+ -scheme Firezone \
+ -sdk ${{ matrix.target.sdk }} \
+ -destination '${{ matrix.target.destination }}'
+ # Move it from randomized build output dir to somewhere we can find it
+ mv ~/Library/Developer/Xcode/DerivedData/Firezone-*/Build/Products/Release/Firezone.app ~/.
+ # Create signed installer pkg
+ productbuild \
+ --sign "${{ env.INSTALLER_CODE_SIGN_IDENTITY }}" \
+ --component ~/Firezone.app /Applications ~/Firezone.pkg
+
+ # Save resulting file to use for upload
+ echo "app_bundle=~/Firezone.pkg" >> "$GITHUB_OUTPUT"
+ else
+ echo "Unsupported platform"
+ exit 1
+ fi
+ - name: Upload build to App Store Connect
+ if: ${{ github.ref == 'refs/heads/main' }}
+ env:
+ ISSUER_ID: ${{ secrets.APPLE_APP_STORE_CONNECT_ISSUER_ID }}
+ API_KEY_ID: ${{ secrets.APPLE_APP_STORE_CONNECT_API_KEY_ID }}
+ API_KEY: ${{ secrets.APPLE_APP_STORE_CONNECT_API_KEY }}
+ run: |
+ # set up private key from env
+ mkdir -p ~/private_keys
+ echo "$API_KEY" > ~/private_keys/AuthKey_$API_KEY_ID.p8
+
+ # Submit app to App Store Connect
+ xcrun altool \
+ --upload-app \
+ -f ${{ steps.build.outputs.app_bundle }} \
+ -t ${{ matrix.target.platform }} \
+ --apiKey $API_KEY_ID \
+ --apiIssuer $ISSUER_ID
- uses: actions/cache/save@v3
if: ${{ github.ref == 'refs/heads/main' }}
name: Save Swift DerivedData Cache
diff --git a/Makefile b/Makefile
index 5ef85c319..8ca67c48e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,10 @@
# Format:
-# MAJOR: This is "1" for now. Don't change it.
-# MINOR: This is the current version of the portal API in YYYYMMDD format. Consumers (connlib, REST) will request
+# MAJOR: This is the marketing version, e.g. 1. Don't change it.
+# MINOR: This is the current version of the portal API in YYYYMMDD format. REST consumers will request
# this API from the portal with the X-Firezone-API-Version request header.
-# PATCH: Increment this each time you want to publish a new Firezone version.
+# Increment this for breaking API changes (e.g. once a quarter)
+# PATCH: Increment this for each backwards-compatible release
+# See discussion here: https://github.com/firezone/firezone/issues/2041
version = 1.20231001.0
.PHONY: version
@@ -14,10 +16,10 @@ SEDARG := -i
endif
version:
- # Elixir can set its Application version from a file, but other components aren't so flexible.
+ @# Elixir can set its Application version from a file, but other components aren't so flexible.
@echo $(version) > elixir/VERSION
@find rust/ -name "Cargo.toml" -exec sed $(SEDARG) -e '/mark:automatic-version/{n;s/[0-9]*\.[0-9]*\.[0-9]*/$(version)/;}' {} \;
@find .github/ -name "*.yml" -exec sed $(SEDARG) -e '/mark:automatic-version/{n;s/[0-9]*\.[0-9]*\.[0-9]*/$(version)/;}' {} \;
@find swift/ -name "project.pbxproj" -exec sed $(SEDARG) -e 's/MARKETING_VERSION = .*;/MARKETING_VERSION = $(version);/' {} \;
- @find kotlin/ -name "build.gradle.kts" -exec sed $(SEDARG) -e '/mark:automatic-version/{n;s/versionName =.*/versionName = "$(version)"/;}' {} \;
+ @find kotlin/ -name "*.gradle.kts" -exec sed $(SEDARG) -e '/mark:automatic-version/{n;s/versionName =.*/versionName = "$(version)"/;}' {} \;
@cd rust && cargo check
diff --git a/swift/apple/Firezone.xcodeproj/project.pbxproj b/swift/apple/Firezone.xcodeproj/project.pbxproj
index b83da9bfa..01ba3579e 100644
--- a/swift/apple/Firezone.xcodeproj/project.pbxproj
+++ b/swift/apple/Firezone.xcodeproj/project.pbxproj
@@ -541,8 +541,9 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = FirezoneNetworkExtension/FirezoneNetworkExtension_iOS.entitlements;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CODE_SIGN_IDENTITY = "Apple Distribution: Firezone, Inc. (47R2M6779T)";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 0;
FRAMEWORK_SEARCH_PATHS = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = FirezoneNetworkExtension/Info.plist;
@@ -564,6 +565,8 @@
OTHER_LDFLAGS = "-lconnlib";
PRODUCT_BUNDLE_IDENTIFIER = "${APP_ID}.network-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "23402aaa-f72c-4947-a795-23a9cf495968";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
@@ -583,8 +586,9 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = FirezoneNetworkExtension/FirezoneNetworkExtension_iOS.entitlements;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CODE_SIGN_IDENTITY = "Apple Distribution: Firezone, Inc. (47R2M6779T)";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 0;
FRAMEWORK_SEARCH_PATHS = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = FirezoneNetworkExtension/Info.plist;
@@ -605,6 +609,8 @@
OTHER_LDFLAGS = "-lconnlib";
PRODUCT_BUNDLE_IDENTIFIER = "${APP_ID}.network-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "23402aaa-f72c-4947-a795-23a9cf495968";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
@@ -624,10 +630,9 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = FirezoneNetworkExtension/FirezoneNetworkExtension_macOS.entitlements;
- CODE_SIGN_IDENTITY = "-";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CODE_SIGN_IDENTITY = "Apple Distribution: Firezone, Inc. (47R2M6779T)";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -647,6 +652,8 @@
OTHER_LDFLAGS = "-lconnlib";
PRODUCT_BUNDLE_IDENTIFIER = "${APP_ID}.network-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "1e965794-0b2c-46d3-a955-d96aacf25546";
SDKROOT = macosx;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = macosx;
@@ -665,10 +672,9 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = FirezoneNetworkExtension/FirezoneNetworkExtension_macOS.entitlements;
- CODE_SIGN_IDENTITY = "-";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CODE_SIGN_IDENTITY = "Apple Distribution: Firezone, Inc. (47R2M6779T)";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES;
@@ -688,6 +694,8 @@
OTHER_LDFLAGS = "-lconnlib";
PRODUCT_BUNDLE_IDENTIFIER = "${APP_ID}.network-extension";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "1e965794-0b2c-46d3-a955-d96aacf25546";
SDKROOT = macosx;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = macosx;
@@ -852,11 +860,9 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Firezone/Firezone.entitlements;
- CODE_SIGN_IDENTITY = "-";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CODE_SIGN_IDENTITY = "Apple Distribution: Firezone, Inc. (47R2M6779T)";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = NO;
DEVELOPMENT_ASSET_PATHS = "\"Firezone/Preview Content\"";
@@ -882,6 +888,9 @@
MARKETING_VERSION = 1.20231001.0;
PRODUCT_BUNDLE_IDENTIFIER = "${APP_ID}";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "b32a5853-699d-4f19-85d3-5b13b1ac5dbb";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "70055d90-0252-4ee5-a60c-4d6f3840ee62";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -904,11 +913,9 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Firezone/Firezone.entitlements;
- CODE_SIGN_IDENTITY = "-";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
+ CODE_SIGN_IDENTITY = "Apple Distribution: Firezone, Inc. (47R2M6779T)";
+ CODE_SIGN_STYLE = Manual;
+ CURRENT_PROJECT_VERSION = 0;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = NO;
DEVELOPMENT_ASSET_PATHS = "\"Firezone/Preview Content\"";
@@ -935,6 +942,9 @@
PRODUCT_BUNDLE_IDENTIFIER = "${APP_ID}";
PRODUCT_MODULE_NAME = "$(PRODUCT_NAME:c99extidentifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "b32a5853-699d-4f19-85d3-5b13b1ac5dbb";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "70055d90-0252-4ee5-a60c-4d6f3840ee62";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
SWIFT_EMIT_LOC_STRINGS = YES;
diff --git a/swift/apple/Firezone/ExportOptions.plist b/swift/apple/Firezone/ExportOptions.plist
new file mode 100644
index 000000000..8caf53fba
--- /dev/null
+++ b/swift/apple/Firezone/ExportOptions.plist
@@ -0,0 +1,16 @@
+
+
+
+
+ method
+ app-store
+ provisioningProfiles
+
+ dev.firezone.firezone
+ b32a5853-699d-4f19-85d3-5b13b1ac5dbb
+
+ dev.firezone.firezone.network-extension
+ 23402aaa-f72c-4947-a795-23a9cf495968
+
+
+
diff --git a/swift/apple/Firezone/Info.plist b/swift/apple/Firezone/Info.plist
index ab64852b2..7f8fc3e87 100644
--- a/swift/apple/Firezone/Info.plist
+++ b/swift/apple/Firezone/Info.plist
@@ -25,5 +25,7 @@
$(CONTROL_PLANE_URL_SCHEME)
ControlPlaneURLHost
$(CONTROL_PLANE_URL_HOST)
+ ITSAppUsesNonExemptEncryption
+
diff --git a/swift/apple/Firezone/xcconfig/Developer.xcconfig.ci-iOS b/swift/apple/Firezone/xcconfig/Developer.xcconfig.ci-iOS
deleted file mode 100644
index 7a10f0302..000000000
--- a/swift/apple/Firezone/xcconfig/Developer.xcconfig.ci-iOS
+++ /dev/null
@@ -1,2 +0,0 @@
-DEVELOPMENT_TEAM = 0000000000
-APP_ID = dev.firezone.ios
diff --git a/swift/apple/Firezone/xcconfig/Developer.xcconfig.ci-macOS b/swift/apple/Firezone/xcconfig/Developer.xcconfig.ci-macOS
deleted file mode 100644
index 8d45d4b25..000000000
--- a/swift/apple/Firezone/xcconfig/Developer.xcconfig.ci-macOS
+++ /dev/null
@@ -1,2 +0,0 @@
-DEVELOPMENT_TEAM = 0000000000
-APP_ID = dev.firezone.macos
diff --git a/swift/apple/Firezone/xcconfig/Developer.xcconfig.firezone b/swift/apple/Firezone/xcconfig/Developer.xcconfig.firezone
new file mode 100644
index 000000000..447850798
--- /dev/null
+++ b/swift/apple/Firezone/xcconfig/Developer.xcconfig.firezone
@@ -0,0 +1,2 @@
+DEVELOPMENT_TEAM = 47R2M6779T
+APP_ID = dev.firezone.firezone
diff --git a/swift/apple/Firezone/xcconfig/Server.xcconfig.dev b/swift/apple/Firezone/xcconfig/Server.xcconfig.dev
new file mode 100644
index 000000000..72c112825
--- /dev/null
+++ b/swift/apple/Firezone/xcconfig/Server.xcconfig.dev
@@ -0,0 +1,4 @@
+AUTH_URL_SCHEME = http
+AUTH_URL_HOST = localhost:8080
+CONTROL_PLANE_URL_SCHEME = ws
+CONTROL_PLANE_URL_HOST = localhost:8081
diff --git a/swift/apple/Firezone/xcconfig/Server.xcconfig.ci b/swift/apple/Firezone/xcconfig/Server.xcconfig.staging
similarity index 60%
rename from swift/apple/Firezone/xcconfig/Server.xcconfig.ci
rename to swift/apple/Firezone/xcconfig/Server.xcconfig.staging
index a261d1ef5..705a357cb 100644
--- a/swift/apple/Firezone/xcconfig/Server.xcconfig.ci
+++ b/swift/apple/Firezone/xcconfig/Server.xcconfig.staging
@@ -1,8 +1,3 @@
-// Configure the Authentication URL and the Control Plane URL
-
-
-// For staging:
-
AUTH_URL_SCHEME = https
AUTH_URL_HOST = app.firez.one
CONTROL_PLANE_URL_SCHEME = wss
diff --git a/swift/apple/Firezone/xcconfig/Server.xcconfig.template b/swift/apple/Firezone/xcconfig/Server.xcconfig.template
index 5746a6156..3bbd46302 100644
--- a/swift/apple/Firezone/xcconfig/Server.xcconfig.template
+++ b/swift/apple/Firezone/xcconfig/Server.xcconfig.template
@@ -1,25 +1,13 @@
-// Configure the Authentication URL and the Control Plane URL
+// This file configures the Authentication URL and the Control Plane URL
+// http or https
+AUTH_URL_SCHEME =
-// For development:
+// auth host and optional port, e.g. app.firezone.dev:443
+AUTH_URL_HOST =
-// AUTH_URL_SCHEME = http
-// AUTH_URL_HOST = localhost:8080
-// CONTROL_PLANE_URL_SCHEME = ws
-// CONTROL_PLANE_URL_HOST = localhost:8081
+// websocket scheme, ws or wss
+CONTROL_PLANE_URL_SCHEME =
-
-// For staging:
-
-// AUTH_URL_SCHEME = https
-// AUTH_URL_HOST = app.firez.one
-// CONTROL_PLANE_URL_SCHEME = wss
-// CONTROL_PLANE_URL_HOST = api.firez.one
-
-
-// For production:
-
-// AUTH_URL_SCHEME = https
-// AUTH_URL_HOST = app.firezone.dev
-// CONTROL_PLANE_URL_SCHEME = wss
-// CONTROL_PLANE_URL_HOST = api.firezone.dev
+// control plane host and optional port, e.g. app.firezone.dev:443
+CONTROL_PLANE_URL_HOST =
diff --git a/swift/apple/README.md b/swift/apple/README.md
index b81ec5c74..2a2242b56 100644
--- a/swift/apple/README.md
+++ b/swift/apple/README.md
@@ -23,7 +23,7 @@ Firezone app clients for macOS and iOS.
1. Rename and populate xcconfig files:
```bash
- cp Firezone/xcconfig/Developer.xcconfig.template Firezone/xcconfig/Developer.xcconfig
+ cp Firezone/xcconfig/Developer.xcconfig.firezone Firezone/xcconfig/Developer.xcconfig
vim Firezone/xcconfig/Developer.xcconfig
```