Code Signing
Guide for signing your Wails applications on all platforms
Code Signing Your Application
This guide covers how to sign your Wails applications for macOS, Windows, and Linux. Wails v3 provides built-in CLI tools for code signing, notarization, and PGP key management.
- macOS - Sign and notarize your macOS applications
- Windows - Sign your Windows executables and packages
- Linux - Sign DEB and RPM packages with PGP keys
Cross-Platform Signing Matrix
This matrix shows what you can sign from each source platform:
| Target Format | From Windows | From macOS | From Linux |
|---|---|---|---|
| Windows EXE/MSI | ✅ | ✅ | ✅ |
| macOS .app bundle | ❌ | ✅ | ❌ |
| macOS notarization | ❌ | ✅ | ❌ |
| Linux DEB | ✅ | ✅ | ✅ |
| Linux RPM | ✅ | ✅ | ✅ |
Signing Backends
Wails automatically selects the best available signing backend:
| Platform | Native Backend | Cross-Platform Backend |
|---|---|---|
| Windows | signtool.exe (Windows SDK) |
Built-in |
| macOS | codesign (Xcode) |
Not available |
| Linux | N/A | Built-in |
When running on the native platform, Wails uses the native tools for maximum compatibility. When cross-compiling, it uses the built-in signing support.
Quick Start
The fastest way to configure signing is the setup wizard:
wails3 setup
This writes a shared signing configuration to ~/.config/wails/defaults.yaml that is
honored at sign time on every platform (see Configuration precedence).
Its signing step:
-
Detects which signing tools are installed for the platform you want to target — from any host — and shows the install command for your OS (e.g.
brew install gnupg,sudo apt install osslsigncode,winget install GnuPG.Gpg4win). -
On macOS, lists Developer ID certificates from your keychain.
-
For Linux, lists your GPG keys and can generate and export a new one.
-
For Windows, can generate a self-signed certificate (for testing) via OpenSSL.
-
Stores passwords securely in your system keychain (not in Taskfiles).
Configuration precedence
When you run a sign task, each signing option is resolved in this order (first
match wins):
- An explicit flag passed to
wails3 tool sign(e.g.--pgp-key,--certificate,--identity). - The matching project Taskfile var (
PGP_KEY,SIGN_CERTIFICATE/SIGN_THUMBPRINT,SIGN_IDENTITY, …). - The global config in
~/.config/wails/defaults.yaml(written bywails3 setup).
This means the Taskfile vars are optional overrides: if a var is unset, the
globally configured key/certificate/identity is used. If none of the three provides
a value, the sign command reports a clear error telling you how to configure it.
Per-project configuration
To configure signing for a single project rather than globally, run the per-project
wizard from inside the project — it writes the vars into that project’s
build/<platform>/Taskfile.yml files:
wails3 setup signing # all detected platforms
wails3 setup signing --platform windows --platform linux
Manual Configuration
Alternatively, you can manually edit the platform-specific Taskfiles. Edit the vars section at the top of each file:
Edit build/darwin/Taskfile.yml:
vars:
SIGN_IDENTITY: "Developer ID Application: Your Company (TEAMID)"
KEYCHAIN_PROFILE: "my-notarize-profile"
# ENTITLEMENTS: "build/darwin/entitlements.plist"Then run:
wails3 task darwin:sign # Sign only
wails3 task darwin:sign:notarize # Sign and notarize
Edit build/windows/Taskfile.yml:
vars:
SIGN_CERTIFICATE: "path/to/certificate.pfx"
# Or use thumbprint instead:
# SIGN_THUMBPRINT: "certificate-thumbprint"
# TIMESTAMP_SERVER: "http://timestamp.digicert.com"Password is retrieved from system keychain (run wails3 setup signing to configure).
Then run:
wails3 task windows:sign # Sign executable
wails3 task windows:sign:installer # Sign NSIS installer
Edit build/linux/Taskfile.yml:
vars:
PGP_KEY: "path/to/signing-key.asc"
# SIGN_ROLE: "builder" # Options: origin, maint, archive, builderPassword is retrieved from system keychain (run wails3 setup signing to configure).
Then run:
wails3 task linux:sign:deb # Sign DEB package
wails3 task linux:sign:rpm # Sign RPM package
wails3 task linux:sign:packages # Sign all packages
You can also inspect signing state from the system directly:
# List available macOS code-signing identities
security find-identity -v -p codesigning
# List PGP keys (Linux package signing)
gpg --list-keys
For interactive setup of every platform’s signing configuration, use the wizard:
wails3 setup signing
macOS Code Signing
Prerequisites
- Apple Developer Account ($99/year)
- Developer ID Application certificate
- Xcode Command Line Tools installed
Signing Identities
Check available signing identities:
security find-identity -v -p codesigning
Output:
Found 2 signing identities:
Developer ID Application: Your Company (ABCD1234) [valid]
Hash: ABC123DEF456...
Apple Development: your@email.com (XYZ789) [valid]
Hash: DEF789ABC123...Configuration
Edit build/darwin/Taskfile.yml and set the signing variables:
vars:
SIGN_IDENTITY: "Developer ID Application: Your Company (TEAMID)"
KEYCHAIN_PROFILE: "my-notarize-profile"
ENTITLEMENTS: "build/darwin/entitlements.plist"| Variable | Required | Description |
|---|---|---|
SIGN_IDENTITY |
Yes | Your Developer ID (e.g., “Developer ID Application: Your Company (TEAMID)”) |
KEYCHAIN_PROFILE |
For notarization | Keychain profile name with stored credentials |
ENTITLEMENTS |
No | Path to entitlements file |
Then run:
wails3 task darwin:sign # Build, package, and sign
wails3 task darwin:sign:notarize # Build, package, sign, and notarize
Entitlements
Entitlements control what capabilities your app has access to. Wails apps typically need different entitlements for development vs production:
- Development: Requires JIT, unsigned memory, and debugging entitlements
- Production: Minimal entitlements (just network access)
Use the interactive setup wizard to generate both files:
wails3 setup entitlements
This creates:
build/darwin/entitlements.dev.plist- For development buildsbuild/darwin/entitlements.plist- For production/signed builds
Presets available:
| Preset | Description |
|---|---|
| Development | JIT, unsigned memory, debugging, network |
| Production | Network only (minimal, most secure) |
| Both | Creates both dev and production files (recommended) |
| App Store | Sandbox enabled with network and file access |
| Custom | Choose individual entitlements |
Then set ENTITLEMENTS in your Taskfile vars to point to the appropriate file.
Notarization
Apple requires all distributed apps to be notarized.
**Store your credentials in the keychain** (one-time setup). Either run `wails3 setup signing` (it prompts for these values and calls `notarytool` under the hood) or call `notarytool` directly:
xcrun notarytool store-credentials "my-notarize-profile" \
--apple-id "your@email.com" \
--team-id "ABCD1234" \
--password "app-specific-password"
**Set KEYCHAIN_PROFILE in your Taskfile** to match the profile name above.
**Sign and notarize your app**:
wails3 task darwin:sign:notarize
**Verify notarization**:
spctl --assess --verbose=2 bin/MyApp.app
Windows Code Signing
Prerequisites
- Code signing certificate (from DigiCert, Sectigo, etc.)
- For native signing on Windows: Windows SDK installed (for
signtool.exe) - For cross-platform signing from macOS/Linux:
osslsigncode(thewails3 setupsigning step shows the host-specific install command)
Generating a self-signed certificate (testing)
If you just need to test the signing pipeline, run wails3 setup, open the
Windows tab of the signing step, and choose Generate a self-signed
certificate. This uses OpenSSL to create a code-signing .pfx and records its
path in the global config.
Configuration
Edit build/windows/Taskfile.yml and set the signing variables:
vars:
SIGN_CERTIFICATE: "path/to/certificate.pfx"
# Or use thumbprint instead:
# SIGN_THUMBPRINT: "certificate-thumbprint"
# TIMESTAMP_SERVER: "http://timestamp.digicert.com"| Variable | Required | Description |
|---|---|---|
SIGN_CERTIFICATE |
Override | Path to .pfx/.p12 certificate file (falls back to global config if unset) |
SIGN_THUMBPRINT |
Override | Certificate thumbprint in Windows cert store (alternative to SIGN_CERTIFICATE) |
TIMESTAMP_SERVER |
No | Timestamp server URL (default: http://timestamp.digicert.com) |
Then run:
wails3 task windows:sign # Build and sign executable
wails3 task windows:sign:installer # Build and sign NSIS installer
Cross-Platform Signing
Windows executables can be signed from any platform. The same Taskfile configuration and commands work on macOS and Linux.
Supported Windows Formats
| Format | Extension | Notes |
|---|---|---|
| Executables | .exe | Standard PE signing |
| Installers | .msi | Windows Installer packages |
| App Packages | .msix, .appx | Modern Windows apps |
Linux Package Signing
Linux packages (DEB and RPM) are signed using PGP/GPG keys. Unlike Windows and macOS code signing, Linux package signing proves the package came from a trusted source rather than that the code is trusted by the OS.
Prerequisites
- PGP key pair (can be generated with Wails)
Generating a PGP Key
The easiest way is the setup wizard — run wails3 setup, open the Linux tab of
the signing step, and choose Create a new GPG key. The wizard:
-
generates an RSA 4096 key in your GPG keyring (leave the passphrase blank for an unattended, CI-friendly key),
-
exports it to
~/.wails/signing/<keyid>.asc(the file a build signs with), and -
records both the key ID and the exported path in
~/.config/wails/defaults.yaml, so it’s used automatically at sign time.
You can also do it by hand with gpg:
# Interactive — the wizard will prompt for name, email, key size and expiry.
gpg --full-generate-key
# Export the key pair to ASCII-armoured files for the Taskfile to consume.
gpg --armor --export-secret-keys "your@email.com" > signing-key.asc
gpg --armor --export "your@email.com" > signing-key.pub.asc
Recommended settings: RSA 4096-bit, 1-year expiry, protected with a strong password.
Configuration
Edit build/linux/Taskfile.yml and set the signing variables:
vars:
PGP_KEY: "path/to/signing-key.asc"
# SIGN_ROLE: "builder" # Options: origin, maint, archive, builder| Variable | Required | Description |
|---|---|---|
PGP_KEY |
Override | Path to the exported PGP private key file (falls back to the key configured globally via wails3 setup if unset) |
SIGN_ROLE |
No | DEB signing role (default: builder) |
Then run:
wails3 task linux:sign:deb # Build and sign DEB package
wails3 task linux:sign:rpm # Build and sign RPM package
wails3 task linux:sign:packages # Build and sign all packages
DEB Signing Roles
For DEB packages, you can specify the signing role via SIGN_ROLE:
origin: Signature from the package originmaint: Signature from the package maintainerarchive: Signature from the archive maintainerbuilder: Signature from the package builder (default)
Cross-Platform Signing
Linux packages can be signed from any platform. The same Taskfile configuration and commands work on Windows and macOS.
Viewing Key Information
gpg --show-keys signing-key.asc
Output:
pub rsa4096 2024-01-15 [SC] [expires: 2025-01-15]
1234 5678 90AB CDEF 1234 5678 90AB CDEF 1234 5678
uid Your Name <your@email.com>Verifying Linux Packages
# Verify DEB signature
dpkg-sig --verify myapp_1.0.0_amd64.deb
# Verify RPM signature
rpm --checksig myapp-1.0.0.x86_64.rpm
Distributing Your Public Key
Users need your public key to verify packages:
# Export public key for distribution
gpg --armor --export "your@email.com" > myapp-signing.pub.asc
# Users can import it:
# For DEB (apt):
sudo apt-key add myapp-signing.pub.asc
# Or for modern apt:
sudo cp myapp-signing.pub.asc /etc/apt/trusted.gpg.d/
# For RPM:
sudo rpm --import myapp-signing.pub.asc
GitHub Actions Integration
In CI environments, passwords are provided via environment variables instead of the system keychain:
| Environment Variable | Description |
|---|---|
WAILS_WINDOWS_CERT_PASSWORD |
Windows certificate password |
WAILS_PGP_PASSWORD |
PGP key password for Linux packages |
You can also pass Taskfile variables directly:
wails3 task darwin:sign SIGN_IDENTITY="$SIGN_IDENTITY" KEYCHAIN_PROFILE="$KEYCHAIN_PROFILE"
macOS Workflow
name: Build and Sign macOS
on:
push:
tags: ['v*']
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Install Wails
run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest
- name: Import Certificate
env:
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
run: |
echo $CERTIFICATE_BASE64 | base64 --decode > certificate.p12
security create-keychain -p "" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" build.keychain
- name: Store Notarization Credentials
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
run: |
xcrun notarytool store-credentials "notarize-profile" \
--apple-id "$APPLE_ID" \
--team-id "$APPLE_TEAM_ID" \
--password "$APPLE_APP_PASSWORD"
- name: Build, Sign, and Notarize
env:
SIGN_IDENTITY: ${{ secrets.MACOS_SIGN_IDENTITY }}
run: |
wails3 task darwin:sign:notarize \
SIGN_IDENTITY="$SIGN_IDENTITY" \
KEYCHAIN_PROFILE="notarize-profile"
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: MyApp-macOS
path: bin/*.appWindows Workflow
name: Build and Sign Windows
on:
push:
tags: ['v*']
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Install Wails
run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest
- name: Import Certificate
env:
CERTIFICATE_BASE64: ${{ secrets.WINDOWS_CERTIFICATE }}
run: |
$certBytes = [Convert]::FromBase64String($env:CERTIFICATE_BASE64)
[IO.File]::WriteAllBytes("certificate.pfx", $certBytes)
- name: Build and Sign
env:
WAILS_WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
wails3 task windows:sign SIGN_CERTIFICATE=certificate.pfx
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: MyApp-Windows
path: bin/*.exeCross-Platform Workflow (Linux Runner)
Sign Windows and Linux packages from a single Linux runner:
name: Build and Sign (Cross-Platform)
on:
push:
tags: ['v*']
jobs:
build-and-sign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: Install Wails
run: go install github.com/wailsapp/wails/v3/cmd/wails3@latest
- name: Install Build Dependencies
run: |
sudo apt-get update
sudo apt-get install -y nsis rpm
# Import certificates
- name: Import Certificates
env:
WINDOWS_CERT_BASE64: ${{ secrets.WINDOWS_CERTIFICATE }}
PGP_KEY_BASE64: ${{ secrets.PGP_PRIVATE_KEY }}
run: |
echo "$WINDOWS_CERT_BASE64" | base64 -d > certificate.pfx
echo "$PGP_KEY_BASE64" | base64 -d > signing-key.asc
# Build and sign Windows
- name: Build and Sign Windows
env:
WAILS_WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
run: |
wails3 task windows:sign SIGN_CERTIFICATE=certificate.pfx
# Build and sign Linux packages
- name: Build and Sign Linux Packages
env:
WAILS_PGP_PASSWORD: ${{ secrets.PGP_PASSWORD }}
run: |
wails3 task linux:sign:packages PGP_KEY=signing-key.asc
# Cleanup secrets
- name: Cleanup
if: always()
run: rm -f certificate.pfx signing-key.asc
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: signed-binaries
path: |
bin/*.exe
bin/*.deb
bin/*.rpmCLI Reference
wails3 setup signing
Interactive wizard to configure signing for your project.
wails3 setup signing [flags]
Flags:
--platform Platform to configure (darwin, windows, linux). Repeatable.
If omitted, auto-detects which platforms to configure from the build directory.
The wizard guides you through:
- macOS: Selecting a Developer ID certificate, configuring notarization credentials (calls
xcrun notarytool store-credentials). - Windows: Choosing between certificate file or thumbprint, setting password and timestamp server.
- Linux: Using an existing PGP key or generating a new one (calls
gpg), configuring signing role.
wails3 setup entitlements
Interactive wizard to configure macOS entitlements.
wails3 setup entitlements [flags]
Flags:
--output Output path for entitlements.plist (default: build/darwin/entitlements.plist)
Presets:
- Development: Creates
entitlements.dev.plistwith JIT, debugging, and network - Production: Creates
entitlements.plistwith minimal entitlements - Both: Creates both files (recommended)
- App Store: Creates sandboxed entitlements for Mac App Store
- Custom: Choose individual entitlements and target file
wails3 sign
Sign binaries and packages for the current or specified platform. This is a wrapper that calls the appropriate platform-specific signing task.
wails3 sign
wails3 sign GOOS=darwin
wails3 sign GOOS=windows
wails3 sign GOOS=linux
This runs the corresponding <platform>:sign task which uses the signing configuration from your Taskfile.
wails3 tool sign
Low-level command to sign a specific file directly. Used internally by the Taskfiles.
wails3 tool sign [flags]
Common Flags:
| Flag | Description |
|---|---|
--input |
Path to the file to sign |
--output |
Output path (optional, defaults to in-place) |
--verbose |
Enable verbose output |
Windows/macOS Flags:
| Flag | Description |
|---|---|
--certificate |
Path to PKCS#12 (.pfx/.p12) certificate |
--password |
Certificate password |
--timestamp |
Timestamp server URL |
macOS-Specific Flags:
| Flag | Description |
|---|---|
--identity |
Signing identity (use ‘-’ for ad-hoc) |
--entitlements |
Path to entitlements plist |
--hardened-runtime |
Enable hardened runtime (default: true) |
--notarize |
Submit for notarization |
--keychain-profile |
Keychain profile for notarization |
Windows-Specific Flags:
| Flag | Description |
|---|---|
--thumbprint |
Certificate thumbprint in Windows store |
Linux-Specific Flags:
| Flag | Description |
|---|---|
--pgp-key |
Path to PGP private key |
--pgp-password |
PGP key password |
--role |
DEB signing role (origin/maint/archive/builder) |
Inspecting signing state (native tools)
There is no wails3 signing command in v3. To inspect signing state, use the native tooling directly:
| Task | Command |
|---|---|
| List macOS code-signing identities | security find-identity -v -p codesigning |
| Store notarization credentials | xcrun notarytool store-credentials "<profile>" --apple-id … --team-id … --password … |
| Inspect a PGP key file | gpg --show-keys <key.asc> |
| Generate a PGP key pair | gpg --full-generate-key |
| Export a public key | gpg --armor --export <email> |
Troubleshooting
macOS Issues
“No Developer ID certificate found”
- Ensure your certificate is installed in the Keychain
- Check it hasn’t expired with
security find-identity -v -p codesigning - Make sure you have a “Developer ID Application” certificate (not just “Apple Development”)
“Notarization failed”
- Check the notarization log:
xcrun notarytool log <submission-id> --keychain-profile <profile> - Ensure hardened runtime is enabled
- Verify your app doesn’t include unsigned binaries
“Codesign failed”
- Make sure the keychain is unlocked:
security unlock-keychain - Check file permissions on the app bundle
Windows Issues
“Certificate not found”
- Verify the certificate path is correct
- Check the certificate password
- Ensure the certificate is valid (not expired or revoked)
“Timestamp server error”
- Try a different timestamp server:
http://timestamp.digicert.comhttp://timestamp.sectigo.comhttp://timestamp.comodoca.com
Linux Issues
“Invalid PGP key”
- Ensure the key file is in ASCII-armored format
- Check the key hasn’t expired with
gpg --show-keys <key.asc> - Verify the password is correct
“Signature verification failed”
- Ensure the public key is properly imported
- Check that the package wasn’t modified after signing