ScreenshotNeo

BlogHow-to

How to Fix Linux Permissions Errors When Running wkhtmltopdf-amd64

Diagnose wkhtmltopdf-amd64 permission errors on Linux: inspect modes, directory access, AppArmor or SELinux, architecture, and conversion settings.

By the ScreenshotNeo team1 October 20267 min read

Start with diagnosis, not a blanket chmod. A Permission denied message can mean the file lacks an execute bit, your user cannot traverse a parent directory, a mandatory access-control policy blocked execution, or the binary does not match your system. Identify the exact file and user first, then apply the narrowest fix.

1. Identify the executable and the account running it

Use an absolute path while troubleshooting. This avoids running a different file with the same name from another directory.

id
pwd
ls -l /path/to/wkhtmltopdf-amd64
file /path/to/wkhtmltopdf-amd64

id shows the user and groups that Linux uses for access checks. ls -l shows the owner, group and mode bits. file helps reveal whether the download is an ELF binary, an AppImage or an incompatible architecture.

If you do not know where the command resolves from, run:

command -v wkhtmltopdf
readlink -f "$(command -v wkhtmltopdf)"

For a file downloaded as wkhtmltopdf-amd64, run the file directly:

/path/to/wkhtmltopdf-amd64 --version

2. Add only the missing execute permission

If the file is trusted, is the intended binary and its mode has no execute bit for your user, grant the owner execute permission:

chmod u+x /path/to/wkhtmltopdf-amd64
/path/to/wkhtmltopdf-amd64 --version

u+x changes only the owner permission. It does not grant access to every user. Avoid chmod 777 and recursive permission changes; they broaden access without addressing the actual cause.

When the download is an AppImage

AppImage’s documented quick start is:

chmod +x my.AppImage
./my.AppImage

See the AppImage quickstart and running AppImages guide. Apply this procedure only when the file is actually an AppImage (or has the same missing execute-bit problem). An AppImage can also be marked executable in the file manager’s permissions panel.

3. Check ownership and every parent directory

Execute permission on the file is not enough. Your user must be able to traverse (x) each directory in the path.

namei -l /path/to/wkhtmltopdf-amd64
ls -ld /path /path/to

Look for a parent directory that denies traversal to your user or one of its groups. Move the binary to a directory you can access, or adjust ownership and group permissions deliberately. Debian’s permissions documentation explains Linux ownership and mode rules.

Do not use sudo as a diagnostic shortcut. Running the command as root can hide a user-access problem and may create root-owned output files. If the program must be installed system-wide, use the package manager or an administrator-approved directory and then test as the service account that will run it.

4. Investigate AppArmor, SELinux and other policy controls

If the mode is executable and directory traversal is allowed, a mandatory access-control policy may be denying the launch or a file the program needs.

AppArmor systems

systemctl status apparmor
sudo aa-status
sudo journalctl -k --since "15 minutes ago" | grep -i apparmor

The wkhtmltopdf AppArmor guide documents checking whether AppArmor is active, reloading a customized profile and reviewing audit logs. A profile must be tailored to your executable, input files, output directory and any helper resources. Do not copy example rules blindly or disable AppArmor globally to make the command run.

SELinux systems

Red Hat-family systems commonly use SELinux instead of AppArmor. Check the enforcement state and recent denials with the tools appropriate to your distribution:

getenforce
sudo ausearch -m avc -ts recent

Use your distribution’s SELinux policy guidance to interpret a denial and create a narrowly scoped rule. The absence of an AppArmor denial does not rule out SELinux, container policy or another security layer.

5. Check mounts, containers and loaders

A filesystem mounted with noexec prevents execution even when the file mode contains x. Inspect the mount containing the binary:

findmnt -T /path/to/wkhtmltopdf-amd64 -o TARGET,SOURCE,FSTYPE,OPTIONS
mount | grep noexec

If the path is on a noexec mount, place the trusted binary on an approved executable filesystem or change the mount policy through your administrator. Do not weaken a security-sensitive mount casually.

In Docker, Kubernetes, CI runners and hardened services, seccomp, user namespaces, read-only filesystems or a restricted service account can produce similar symptoms. Compare the identity and mounts inside the container with those on the host:

id
cat /proc/mounts
uname -m

An ELF interpreter or shared-library problem often reports a different message such as “No such file or directory” or “cannot execute.” Inspect dependencies only after confirming the file type and architecture:

ldd /path/to/wkhtmltopdf-amd64
uname -m

6. Confirm the package, distribution and architecture

The wkhtmltopdf project no longer provides one generic Linux build. Its downloads page lists distribution- and architecture-specific packages and identifies stable version 0.12.6, released June 11, 2020. That page does not establish which version is installed on your machine.

Before replacing a binary, record the environment and package origin:

cat /etc/os-release
uname -m
# Debian or Ubuntu packages
apt-cache policy wkhtmltopdf
# RPM-based systems
rpm -qf /path/to/wkhtmltopdf-amd64 2>/dev/null || true

Choose an artifact for the exact distribution release and CPU architecture. If a package cannot be installed and you extract it manually, install its documented runtime dependencies rather than changing permissions broadly.

7. Separate launch errors from conversion-time file access

Once wkhtmltopdf-amd64 --version starts, a later error about reading a local HTML file, stylesheet or image is a different stage. The Ubuntu and Debian manpages document --disable-local-file-access and --allow <path> for conversion-time local-file access:

/path/to/wkhtmltopdf-amd64 \
  --disable-local-file-access \
  --allow /srv/site/assets \
  input.html output.pdf

These flags do not grant permission to launch the executable. Review the Ubuntu manpage or Debian Bookworm manpage for conversion options. The project also cautions that untrusted HTML should be handled with appropriate confinement.

8. A complete diagnostic checklist

  1. Capture the literal error, current directory and command line.
  2. Run id, ls -l, file and namei -l against the absolute path.
  3. Verify the file is trusted and add chmod u+x only when the user execute bit is missing.
  4. Run --version before attempting a conversion.
  5. Inspect mount options for noexec.
  6. Check AppArmor or SELinux audit logs for a denial.
  7. Confirm distribution, architecture, package provenance and runtime dependencies.
  8. After launch works, diagnose input-file access separately with --allow or the appropriate conversion setting.

Common errors and fixes

Symptom Likely layer Action
Permission denied immediately File mode, parent directory, policy or noexec mount Run ls -l, namei -l, findmnt and policy-audit checks; add only the missing execute bit.
chmod +x changes nothing Wrong file, inaccessible parent, policy denial or noexec Use an absolute path and inspect the mount and security logs.
No such file or directory for an existing binary Missing ELF loader or incompatible architecture Run file, uname -m and ldd; obtain a compatible package.
AppArmor or SELinux audit denial Mandatory access control Adjust the profile for required paths and reload it; do not disable the framework globally.
Binary starts, HTML assets fail Conversion-time local-file restriction Use an explicit, narrow --allow path or revise the input; this is separate from launch permissions.

Performance, reliability and security notes

  • Keep the executable on a local filesystem with predictable mount options; network filesystems and container overlays can add policy and latency variables.
  • Run under the same non-root account, environment and working directory used by production jobs.
  • Pin the package source and verify the downloaded artifact before granting execute permission.
  • Limit AppArmor or SELinux permissions to the input, output and helper paths the conversion actually needs.
  • Use timeouts and capture stderr in automation so a policy denial is distinguishable from a conversion failure.
  • Do not process untrusted HTML without confinement; wkhtmltopdf’s project documentation discusses restricting filesystem access and execution.

Or skip the browser setup

If your real goal is a clean screenshot or PDF rather than maintaining a local wkhtmltopdf installation, ScreenshotNeo provides a hosted capture API. See the API documentation for all options.

# cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

# Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

// Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Cookie banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages and failed loads are never billed, and response headers identify the page verdict and billing status. An MCP server lets AI agents use take_screenshot, get_page_info and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.

Create a free ScreenshotNeo account.

FAQ

Should I run sudo chmod +x?

Usually no. Grant execute permission to the intended owner with chmod u+x and run the command as the account that needs it.

Does --allow fix a permission denied launch?

No. It controls which local files wkhtmltopdf may read after the program has started.

Why does the filename end in -amd64?

It commonly indicates a 64-bit x86 build, but confirm with file and uname -m instead of relying on the name.

Can I disable AppArmor or SELinux temporarily?

Use audit evidence to create a narrow policy adjustment. Broadly disabling mandatory access control removes protections and does not identify the underlying access requirement.

What information should I include when asking for help?

Include the exact command and error, output of id, ls -l, file, namei -l, your distribution and release, CPU architecture, mount options and any AppArmor or SELinux denial.