To launch Edge or Chrome with Puppeteer on an IIS server using Windows Authentication and a Managed Service Account (MSA), you must configure the application pool to run under that specific identity and ensure the browser executable has explicit read and execute permissions for that account. Additionally, you need to disable the sandbox mode in Puppeteer because the MSA often lacks the necessary privileges to create the required inter-process communication channels within the restricted IIS environment.
Configuring the Application Pool Identity
The foundation of this setup is ensuring that the IIS worker process runs under the context of your Managed Service Account. If the application pool is running under the default
IIS AppPool\DefaultAppPool identity, Puppeteer will attempt to spawn browsers using those limited credentials, which frequently leads to permission denied errors or silent failures during headless execution.
Navigate to the IIS Manager on your server. In the Connections pane on the left, expand your server node and select
Application Pools. Locate the application pool associated with your Puppeteer-based web application. Right-click it and select
Advanced Settings.... Scroll down to the
Process Model section and find the
Identity property. Change this from
ApplicationPoolIdentity to
Custom Account. Click the [...] button to browse for your MSA. You typically enter the username as
YourDomain\YourManagedServiceAccount without needing to provide a password, as MSAs manage their own Kerberos keys automatically. Once set, restart the application pool to apply the changes. This ensures that any child processes spawned by Node.js inherit the security token of the MSA.
Granting File System Permissions
Even with the correct identity, the operating system may block the browser from launching if the service account cannot access the binary files. Browsers like Microsoft Edge and Google Chrome are installed in protected directories such as
C:\Program Files (x86)\Microsoft\Edge\Application or
C:\Program Files\Google\Chrome\Application. By default, standard users and service accounts do not have full control over these folders.
You must grant the MSA at least Read & Execute permissions on the browser's installation directory. Open File Explorer, navigate to the root folder of the browser you intend to use. Right-click the folder and select
Properties, then go to the
Security tab. Click
Edit and then
Add. Enter the name of your Managed Service Account and verify it exists. Select the account from the list and check the box for
Read & execute,
List folder contents, and
Read. Apply these changes recursively to all subfolders and files. Without these permissions, the
child_process module used by Puppeteer will fail to start the executable silently or throw an immediate access violation error.
Disabling Browser Sandbox Mode
This is the most critical technical adjustment for Puppeteer in server environments. Modern browsers utilize a "sandbox" architecture where renderer processes run with significantly reduced privileges to enhance security. When IIS spawns a browser under an MSA, the account often does not have the right to create the shared memory segments or named pipes required for the sandbox to function correctly. Consequently, the browser crashes immediately upon launch.
You can resolve this by instructing Puppeteer to launch the browser with the sandbox disabled. In your Node.js code, when defining the Puppeteer launch arguments, include the flag
--no-sandbox. For example:
const browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox'
]
});
The
--no-sandbox argument tells the browser to skip the creation of the isolated user namespace and shared memory structures that require elevated privileges. The
--disable-setuid-sandbox flag further ensures that the browser does not attempt to change its own user ID, which is another common point of failure for service accounts. While disabling the sandbox reduces the security isolation between tabs, it is generally acceptable for internal automation tasks where the risk of cross-site scripting attacks leading to privilege escalation is mitigated by other network and application-level controls.
Handling User Data Directories
Puppeteer requires a dedicated user data directory to store cookies, cache, and session state. By default, it creates this in a temporary location. However, IIS applications sometimes face restrictions when writing to certain temp folders depending on the strictness of the Windows Server configuration. It is best practice to explicitly define a persistent directory for the user data.
When launching the browser, specify the
userDataDir option:
const browser = await puppeteer.launch({
userDataDir: 'C:\\PuppeteerUserData\\MyApp',
args: ['--no-sandbox']
});
Ensure that the MSA has Full Control permissions over this specified directory. If the directory does not exist, Puppeteer will attempt to create it, but pre-creating it and setting the permissions via PowerShell or the GUI prevents race conditions during startup. This also makes debugging easier, as you can inspect the local storage and cookies directly from the file system if the automation behaves unexpectedly.
Related Configuration Considerations
If you encounter issues after implementing these steps, consider reviewing how your server handles external connectivity. Sometimes, network policies restrict the browser from reaching update servers or telemetry endpoints, causing timeouts. You might also want to look into
Adding Private key SSL Cert to IIS if your Puppeteer scripts need to interact with internal HTTPS sites that rely on self-signed certificates, as the browser instance launched by Puppeteer will validate these certs independently of the IIS configuration.
Frequently Asked Questions
Why does Puppeteer work locally but fail on IIS?
It fails because the local developer machine usually runs with administrator rights or a standard user profile that has full access to browser sandboxes and temp folders. IIS runs under a highly restricted service account (MSA) that lacks the kernel-level permissions required for sandboxed processes. Disabling the sandbox and adjusting file permissions bridges this gap.
Can I use the default ApplicationPoolIdentity instead of an MSA?
Yes, but you still need to disable the sandbox. The
IIS AppPool\DefaultAppPool identity is essentially a virtual account that behaves similarly to a local service account. It faces the same sandbox restrictions as an MSA. Therefore, the
--no-sandbox flag is mandatory regardless of whether you use an MSA or the default app pool identity.
How do I debug why the browser is crashing on startup?
Enable verbose logging in Puppeteer by setting the environment variable
PUPPETEER_LOG_LEVEL=debug before launching the script. Check the Windows Event Viewer under Applications and Services Logs for .NET Runtime or Node.js errors. Often, the crash log will indicate a specific missing DLL or a permission denied event related to the user data directory.
Is it safe to disable the browser sandbox in production?
For automated testing and scraping tasks that do not handle sensitive user input, the risk is low. However, if your Puppeteer instance is exposed to untrusted URLs, disabling the sandbox increases the attack surface. Always ensure your IIS server is isolated from the public internet and that the MSA has minimal privileges outside of the browser execution requirement.
What should I do if the MSA password expires?
Managed Service Accounts (gMSAs) manage their own passwords automatically and they do not expire in the traditional sense. If you are using a standard Virtual Account, it also manages its own credentials. If you see authentication errors, it is likely due to a group policy refresh issue or a trust relationship problem between the domain controller and the server hosting IIS, rather than a password expiry.