---
title: PhotoStructure for Node
url: https://photostructure.com/server/photostructure-for-node/
description: Instructions for installing PhotoStructure for Node
date: 2023-11-13
keywords: Node.js, installation, Linux, macOS, Windows, troubleshooting, systemd
---


These are instructions for advanced users who want to run [PhotoStructure on a
server](/server/photostructure-for-servers/) without Docker.

If you have questions or get stuck, hop into the
[forum](//forum.photostructure.com) or
[discord](//photostructure.com/go/discord). We'll help get you set up!

## Prerequisites

PhotoStructure for Node requires:

- agreement to all terms in the [end-user license](/terms/eula/)

- a 64-bit Intel or AMD CPU. Note that Apple Silicon and Linux ARM support is experimental.

- Ubuntu LTS 22.04 or later, Fedora 38 or later, Windows 10, Windows 11, or macOS 15 (Sequoia) or later.

- [Node.JS](https://nodejs.org/en/) (version 22.3 or later, version 24 recommended).

{{% note %}}
Never run any command on your terminal that you don't understand.<br>
Hop into our [Discord](/go/discord) if you have any questions.
{{% /note %}}

## Contents

We've got instructions for the following operating systems:

- [<img src="/img/ubuntu-dark.svg" class="dib svg" /> Ubuntu ](#ubuntu-install)
- [<img src="/img/fedora-dark.svg" class="dib svg" /> Fedora ](#fedora-install)
- [<img src="/img/apple-dark.svg" class="dib svg" /> macOS ](#macos-install)
- [<img src="/img/win10-dark.svg" class="dib svg" /> Windows 10 / Windows 11](#win10-install)
- [<img src="/img/rpi-dark.svg" class="dib svg" /> Raspberry Pi](/server/photostructure-for-rpi/)

<a id="ubuntu-install"></a>

## 🐧 Installation for Ubuntu

### Step 1: Consider hardening your server

Instructions for "server hardening" are [**on the forum**](https://forum.photostructure.com/t/server-hardening-101/1027).

### Step 2: Install prerequisite packages

Open a terminal and run:

```sh
sudo apt install build-essential python3-dev \
  git perl libjpeg-turbo-progs libheif-examples heif-thumbnailer ffmpeg
```

{{% tip %}}
**Ubuntu 22.04 users:** The default `libheif-examples` (1.12.0) cannot handle HEIC files from newer iPhones. See the [media codec support page](/getting-started/media-codec-support/#heif-linux) for instructions to install a newer version via PPA.
{{% /tip %}}

Notes:

- `build-essential` and `python3-dev` compile several native libraries that accelerate image and database operations.
- `git` fetches and updates the PhotoStructure source code.
- `perl` runs [ExifTool](https://exiftool.org) for reading and writing metadata in images, videos, and sidecars.
- `libjpeg-turbo-progs` validates and manipulates JPEG images.
- `libheif-examples` adds [HEIF image support](/getting-started/media-codec-support/).
- `heif-thumbnailer` speeds up [HEIF thumbnail generation](/getting-started/media-codec-support/).
- `ffmpeg` adds [video support](/getting-started/media-codec-support/).

<a id="ubuntu-post-setup"></a>

### Step 3: Create a role user to run PhotoStructure

Create a dedicated role user to run PhotoStructure, as you would for any service.

```sh
sudo adduser --disabled-password photostructure
```

This role user needs **read** access to your photos and videos, and **write** access to

1. the directory that holds your [PhotoStructure library](/faq/library/)
2. `~photostructure/.config/PhotoStructure` (the system settings directory)
3. `~photostructure/.cache/PhotoStructure` (the scratch directory)

Note:

- The system settings directory default can be changed by setting the
  `PS_CONFIG_DIR` environment variable.
- The scratch directory can be changed by setting the `PS_CACHE_DIR` environment
  variable.
- Read more about [advanced settings](/getting-started/advanced-settings/).

### Step 4: Install Node.js

Two options for installing Node.js:

#### Option 1, via your package manager

This installs Node.js via [NodeSource](https://github.com/nodesource/distributions) packages.

Node.js gets security updates automatically whenever you run `apt update && apt upgrade`. The tradeoff: initial setup is a bit more involved than `nvm`, and you can only have one version of Node.js installed at a time.

1. Download and import the Nodesource GPG key

```sh
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
  | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
```

2. Set up the deb repository:

```sh
NODE_MAJOR=24
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" \
  | sudo tee /etc/apt/sources.list.d/nodesource.list
```

3. Run update and install:

```sh
sudo apt-get update
sudo apt-get install nodejs -y
```

<a id="npm-prefix"></a>

4. Then configure `npm`:

```sh
export NPM_PREFIX=~/.npm
mkdir -p "$NPM_PREFIX"

npm config set prefix "$NPM_PREFIX"

if [ -r ~/.bashrc ]; then
  echo "export PATH=\"\$PATH:$NPM_PREFIX/bin\"" >> ~/.bashrc
else
  echo "Please add $NPM_PREFIX/bin to your shell login script"
fi
```

This last step configures `npm` to write globally-installed packages into
`~/.npm`, instead of the default, which is to write to
`/usr/lib/node_modules`, which is a system directory that no user should have
write-access to.

[More information about the `prefix` setting is on the npmjs.com website](https://docs.npmjs.com/cli/v10/configuring-npm/folders#prefix-configuration).

<a id="nvm"></a>

#### Option 2, via `nvm`:

If you have any other software on your server that needs a different version of Node.js you may want to use `nvm` instead.

[Node Version Manager](https://github.com/nvm-sh/nvm#installing-and-updating), or `nvm`, manages one or more versions of Node.js, per user.

```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
```

and then restart your shell, and run

```sh
nvm install 24 --latest-npm
```

_Security updates to Node.js will not be applied automatically_. When a new version is available, you need to run `nvm install 24 --latest-npm`.

#### Notes

- Consider curling (any!) setup script to a file and reviewing the file before executing as root.
- You will have performance problems if you use the snap version of Node.js.

### Step 5: Download and start PhotoStructure

This assumes you’re going to install PhotoStructure into your new role user’s
home directory, `~photostructure`.

```sh
sudo --login --user photostructure bash

cd ~photostructure

git clone https://github.com/photostructure/photostructure-for-servers.git

cd photostructure-for-servers

./start.sh
```

Jump to the [Start PhotoStructure](#start) section for more information.

<a id="systemd"></a>

### Step 6: Set up a systemd service (optional)

Use the **[systemd wizard](/server/systemd/)** to generate a unit file
tailored to your setup. The wizard covers Node.js version managers, library
directory, security hardening, watchdog monitoring, and troubleshooting.

<a id="fedora-install"></a>

## 🐧 Installation for Fedora

### Step 1: Consider hardening your server

Instructions for "server hardening" are [**on the forum**](https://forum.photostructure.com/t/server-hardening-101/1027).

### Step 2: Install prerequisite packages

Open a terminal and run:

```sh
sudo dnf install @development-tools \
  git perl libjpeg-turbo-utils libheif-tools ffmpeg
```

Notes:

- `@development-tools` compiles several native libraries needed by PhotoStructure.
- `git` fetches and updates the PhotoStructure source code.
- `perl` runs [ExifTool](https://exiftool.org) for reading and writing metadata in images, videos, and sidecars.
- `libjpeg-turbo-utils` validates and manipulates JPEG images.
- `libheif-tools` adds [HEIF image support](/getting-started/media-codec-support/).
- `ffmpeg` adds [video support](/getting-started/media-codec-support/).

### Step 3: Install Node.js

You can either install with [NodeSource](https://github.com/nodesource/distributions#fedora-versions) or with [nvm](#nvm).

Pick NodeSource if you want Node.js to get updated automatically by `yum`/`dnf`. If you need to run multiple versions of Node.js concurrently, `nvm` is a
better route, but note that upgrades, even for security issues, are manual.

#### NodeSource

```
sudo yum install https://rpm.nodesource.com/pub_24.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y
sudo yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1
```

And then set up [`npm prefix` with these steps](#npm-prefix).

#### nvm

[Set up nvm with these steps](#nvm).

### Step 4: Finish

The remaining installation steps are the same as on Ubuntu.
[Follow along here](#ubuntu-post-setup).

<a id="macos-install"></a>

## 🍎 Installation for macOS

PhotoStructure needs the following:

- [Xcode](https://developer.apple.com/xcode/)'s command line tools,
- [Node.js v24](https://nodejs.org/en/),
- [ffmpeg](https://ffmpeg.org/),
- [jpeg-turbo](https://www.libjpeg-turbo.org/), and
- [Python](https://www.python.org/)

You're free to install these by yourself, but [homebrew](https://brew.sh/) makes this much easier.

### Step 1: Install Xcode command line tools

Open Terminal.app and run this:

```sh
xcode-select --install
sudo xcode-select --reset
```

Note that `xcode-select` will take several minutes to install.

### Step 2: Install [homebrew](https://brew.sh/)

Open a terminal and run:

```sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

At the end of this command, there are instructions to add homebrew to your
PATH. Make sure you do that! It'll look something like this:

```sh
(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile

eval "$(/opt/homebrew/bin/brew shellenv)"
```

### Step 3: Install PhotoStructure's dependencies

In a terminal, run the following:

```sh
brew doctor && brew upgrade && brew install -q ffmpeg jpeg-turbo python python-setuptools node@24
```

**Note that the list of homebrew packages changes regularly with new versions of PhotoStructure**.

If you're upgrading, `start.sh` will run this command for you automatically when it detects macOS and homebrew, unless you set `NOBREW=1`.

What's all this?

- `brew doctor` verifies your system setup looks OK.
- `brew upgrade` ensures we're getting the latest version of everything.
- `brew install ffmpeg` installs [FFmpeg](https://www.ffmpeg.org), used for [video encoding](/video).
- `brew install jpeg-turbo` installs JPEG tooling used by PhotoStructure to validate images.
- `brew install python python-setuptools` installs both Python 3 and distutils, required to compile PhotoStructure's native libraries.
- `brew install node@24` installs [Node.js](https://nodejs.org). PhotoStructure is a Node.js application.

**Note that installing Node.js will emit some instructions that you must follow.** They'll look something like this:

```sh
echo 'export PATH="/opt/homebrew/opt/node@24/bin:$PATH"' >> ~/.zshrc
echo 'export LDFLAGS="-L/opt/homebrew/opt/node@24/lib"' >> ~/.zshrc
echo 'export CPPFLAGS="-I/opt/homebrew/opt/node@24/include"' >> ~/.zshrc
source ~/.zshrc
```

### Step 4: Download PhotoStructure

In a terminal, run

```sh
cd ~ # or wherever you want to put the code that runs PhotoStructure (it's less than a GB)

git clone https://github.com/photostructure/photostructure-for-servers.git

cd photostructure-for-servers

./start.sh
```

Jump to the [Start PhotoStructure](#start) section for more information.

<a id="win10-install"></a>

## 🪟 Installation for Windows 10/11

### Step 1: Install Git

Install [Git for Windows](https://git-scm.com/download/win).

- You want the "64-bit Git for Windows" installer option.

- [Scan the installer for viruses before running](/faq/scan-for-viruses/).

- The git installer asks a _lot_ of questions: PhotoStructure will work fine
  if you accept all the defaults. Hop into
  [Discord](/go/discord) if you have questions,
  though!

### Step 2: Install Node.js

Install [Node.js](https://nodejs.org/) version 22 or later (version 24 recommended).

- [Scan the installer for viruses before running](/faq/scan-for-viruses/).

- Keep "Add to PATH" selected.

- On the last screen, select "Automatically install the necessary tools.":

{{< figure src="/img/2020/07/choco-node.png" class="mw6" >}}

The installation will take a while, as the Node.js installer will install
[Chocolatey](https://chocolatey.org/), and then ask `choco` to install the tools
necessary to build native modules. PhotoStructure uses several of these modules,
so this step cannot be skipped.

### Step 3: Install JPEG and video support

If you want to install video support, after installing `node` and the build
tools finish installing, open a new Administrator PowerShell, and run:

```sh
choco install ffmpeg jpegtran
```

Wait for the installations to finish, and then close the PowerShell window
by typing `exit` and hitting return.

### Step 4: Install HEIF support

If you have a recent iPhone or Samsung smartphone, you probably have
HEIF-encoded photos. [Follow these HEIF installation
instructions](/getting-started/media-codec-support/#windows-heif). Note that this is optional.

### Step 5: Download PhotoStructure

In a new `Git Bash` terminal (don't use `cmd` or PowerShell!), run these
commands:

```sh
npm install --global yarn npm

cd ~ # (or whatever directory you want to install PhotoStructure into)

git clone https://github.com/photostructure/photostructure-for-servers.git

cd photostructure-for-servers

./start.sh
```

Note:

- `npm install --global yarn npm` installs
  [yarn](https://classic.yarnpkg.com/en/docs/install#debian-stable) and makes sure
  [npm](https://docs.npmjs.com/cli/v8/commands/npm) is the latest available version.

- `start.sh` downloads and installs some additional software (like
  [exiftool-vendored](https://github.com/photostructure/exiftool-vendored.js)).

  This can take a while, but it only happens after PhotoStructure or
  Node.js is upgraded. Subsequent restarts should be quick.

### Step 6: Automatic launch at startup

If you want PhotoStructure to run at startup, [follow these
instructions](https://forum.photostructure.com/t/how-to-run-photostructure-for-node-automatically-on-windows-startup/928).

<a id="start"></a>

## 🚀 Starting PhotoStructure

```sh
cd ~photostructure/photostructure-for-servers # or wherever you cloned the repo
./start.sh
```

It prints a localhost URL to open in a browser. Chrome, Firefox, and Safari are supported on desktop and mobile.

### Notes

- The `./start.sh` script is short and only runs "bootstrap.js" and then "photostructure.js".

  In prior versions of PhotoStructure for Node, whenever there were updates to
  `start.sh`, bash would lose track of where it was after the upgrade, which
  could cause confusing and non-reproducible errors. In v2024.5 we moved as
  much as possible into `bootstrap.js`. This should be transparent to you.

- The startup process verifies that `node`, `git`, `python`, and other required tools are installed. It then runs `git pull`, installs dependencies with `yarn`, and launches PhotoStructure.

- You can use `./start.sh --help` to see more detailed usage information.

- The first time you run `start.sh`, it will download and compile dependencies,
  which will take a moment, and then launch PhotoStructure. Subsequent starts
  will be much faster, unless there is a new release or your version of node is
  upgraded. Recompilation happens automatically.

- PhotoStructure currently binds to **localhost only** by default, so if you
  want to access it elsewhere, you need to either set the
  **`exposeNetworkWithoutAuth`** [library
  setting](/getting-started/advanced-settings/) to
  true, or set the environment variable `PS_EXPOSE_NETWORK_WITHOUT_AUTH` to 1.
  PhotoStructure has no built-in authentication, so only expose it on networks you trust.

- If you use the `--pidfile $PIDFILE` option, the process will daemonize and
  return you to your shell prompt.

### Advanced options

## ⏹️ Shutting down PhotoStructure

It's easiest to shut down PhotoStructure via the navigation menu (the
"hamburger" icon in the upper right corner of the UI).

If you’re running `start.sh` in the foreground in a terminal, just hit ctrl-c. The `photostructure main` process shuts down gracefully on `SIGINT`.

If you’ve daemonized it with a `--pidfile`, run something like `./photostructure --stop --pidfile /var/run/photostructure.pid`.

### Why is it taking so long to shut down?

PhotoStructure may take up to a minute to shut down, depending on the size of
your library and disk speed. Closing the library database requires copying it
back to your library when it's hosted on a remote filesystem.

## ⬆️ Upgrading PhotoStructure

If you're using `systemd`, just run `sudo systemctl restart photostructure` to pick up the new release.

Otherwise, shut down and restart PhotoStructure: `./start.sh` checks for new versions every time it starts.

## Switching between beta and stable release channels

The "release channel" you're using is based on the `git branch` you've checked out.

If, for any reason, you want to switch to the "stable" release, open a terminal and run

```sh
sudo su - photostructure
cd ~/photostructure-for-servers
git fetch
git stash -u
git checkout main
```

[Read this forum post to learn more about different release channels (beta and stable).](https://forum.photostructure.com/t/beta-stable-and-latest-what-should-you-use/274)

## Advanced settings in `./start.sh` / `bootstrap.js`

The `start.sh` script supports several environment variable settings to let it behave as you want:

- Set `PS_CHECK_UPDATES=none`, or `PS_NO_GIT=1` to prevent automatic version upgrades

- Set `NOBREW=1` on macOS to disable automatic homebrew installs and package upgrades

- Set `NODE=/path/to/node` to use a specific path to a Node.js binary

- Set `GIT=/path/to/git` to use a specific `git` binary

- Set `PYTHON=/path/to/python3` to use a specific Python 3.x

- Set `PIP=/path/to/python3` to use a specific Python package installer command

- Set `PS_CONFIG_DIR` to override PhotoStructure's default configuration directory

- Set `PS_NO_NETWORK=1` to tell PhotoStructure it cannot make external network requests. See below for details.

- <a id="psenv"></a>Set `PS_ENV_FILE=/path/to/file.env` if you want a `.env` file to override any settings. [This is explained in detail here](/go/psenv).

## Troubleshooting

If you run into problems during installation or startup, find your error message in the sections below.

<a id="troubleshooting-node-version"></a>

### Node.js version is too old or missing

PhotoStructure v2026.2+ requires Node.js v22.3 or later (v24 recommended). v22.3 is needed for `zlib.crc32` support. The startup script checks both that `node` exists in your `PATH` and that the version is recent enough.

**Check your version:**

```sh
node -v
```

If this prints nothing or "command not found", Node.js isn't installed (or isn't in your `PATH`).

**To fix:**

- **Ubuntu:** Follow the [NodeSource](#ubuntu-install) or [nvm](#nvm) instructions above.
- **Fedora:** Follow the [Fedora NodeSource](#fedora-install) or [nvm](#nvm) instructions above.
- **macOS:** `brew install node@24` (see the [macOS steps](#macos-install)).
- **Windows:** Download the latest installer from [nodejs.org](https://nodejs.org/) (see the [Windows steps](#win10-install)).

If you installed Node.js with `nvm`, make sure your shell profile runs `nvm use` so the correct version is active in new terminals and systemd services.

<a id="troubleshooting-prerequisites"></a>

### Missing git, npm, or python

**Error:**

- `Please install git`
- `Please reinstall Git (missing git)`
- `Please reinstall Node.js (missing npm)`
- `Please reinstall Python (missing python3)`

The bootstrap script checks for `git`, `npm`, and `python3` (or `git.exe`, `npm.cmd`, and `py.exe` on Windows) in your `PATH`.

**Check what's installed:**

```sh
git --version
npm --version
python3 --version   # or py --version on Windows
```

**To fix:**

- **Ubuntu:** `sudo apt install git build-essential python3-dev` (see [Step 2](#ubuntu-install))
- **Fedora:** `sudo dnf install git @development-tools` (see [Step 2](#fedora-install))
- **macOS:** `xcode-select --install` for git, `brew install python python-setuptools node@24` for the rest (see [macOS steps](#macos-install))
- **Windows:** Install [Git for Windows](https://git-scm.com/download/win) and [Node.js](https://nodejs.org/) with the "Automatically install necessary tools" option checked (see [Windows steps](#win10-install))

If the tools are installed but not found, check that their directories are in your `PATH` environment variable.

<a id="troubleshooting-npm-install"></a>

### npm install failures

If `npm install` fails during bootstrap, it's usually a compilation error or a network timeout.

**Diagnostic steps:**

```sh
# Can npm reach the registry?
npm ping

# What registry and proxy are configured?
npm config list

# Clear the cache and retry
npm cache clean --force
./start.sh
```

**Common causes:**

- **Missing build tools:** On Ubuntu, install `build-essential` and `python3-dev`. On Fedora, install `@development-tools`. On Windows, make sure you checked "Automatically install necessary tools" during the Node.js install.
- **Proxy:** If you're behind a corporate proxy, configure npm: `npm config set proxy http://your-proxy:port`
- **Stale cache:** `npm cache clean --force` and retry.
- **Permission errors:** Never run `npm install` with `sudo`. If you see `EACCES` errors, check that your [`npm prefix`](#npm-prefix) is set to a directory you own.

<a id="troubleshooting-network"></a>

### Network disabled on first run

**Error:** `Network access is disabled. Please enable your WAN during your first run to download PhotoStructure's dependencies.`

The first startup downloads npm packages and pulls the latest code from GitHub. After that initial install, PhotoStructure can run fully offline.

**To fix:**

1. Make sure your server can reach `registry.npmjs.org` and `github.com`.
2. If you set `PS_NO_NETWORK=1`, remove it for the initial install.
3. Run `./start.sh` again.

Once the first run completes, you can set `PS_NO_NETWORK=1` for subsequent launches. See the [offline section below](#offline) for details.

<a id="troubleshooting-python"></a>

### Python distutils / setuptools missing

**Error:** `Failed to install Python setuptools` or `No module named 'distutils'`

Python 3.12+ [removed `distutils`](https://docs.python.org/3.12/whatsnew/3.12.html#distutils) from the standard library ([PEP 632](https://peps.python.org/pep-0632/)). PhotoStructure needs it (via `setuptools`) to compile native modules.

**Check if `distutils` is available:**

```sh
python3 -c "import distutils"
```

If that fails with `ModuleNotFoundError`, install `setuptools`:

- **Ubuntu:** `sudo apt install python3-setuptools` (or `pip3 install setuptools`)
- **Fedora:** `sudo dnf install python3-setuptools`
- **macOS:** `brew install python-setuptools` (see [macOS Step 3](#macos-install))
- **Windows:** `pip install setuptools` (or `py -m pip install setuptools`)

If `pip` itself is missing: `python3 -m ensurepip --upgrade` (Linux/macOS) or reinstall Python from [python.org](https://www.python.org/) with the "pip" option checked (Windows).

<a id="troubleshooting-unexpected"></a>

### Unexpected errors

**Error:** `PhotoStructure setup failed.`, `Unexpected rejection:`, or `Unexpected error:` (possibly followed by a stack trace)

These are catch-all errors from bootstrap. Common causes: filesystem permission problems, corrupted `node_modules`, or missing system libraries.

**Try this first:**

```sh
# Wipe node_modules and reinstall from scratch
rm -rf node_modules
./start.sh
```

**If that doesn't help:**

```sh
# Check filesystem permissions
ls -la ~photostructure/photostructure-for-servers/

# Run with debug logging to get more detail
PS_LOG_LEVEL=debug ./start.sh
```

If the error persists, copy the full output and post it on the [forum](https://forum.photostructure.com/) or [Discord](https://photostructure.com/go/discord). Include your OS version, Node.js version (`node -v`), and Python version (`python3 --version`).

<a id="offline"></a>

## Does PhotoStructure support offline installations?

PhotoStructure only needs WAN access to NPM and GitHub during version upgrades. If your external network is unavailable when PhotoStructure launches, it detects this and starts in "no network" mode. You can force this mode by setting `PS_NO_NETWORK=1`.

Note that PLUS license renewals require the browser viewing your PhotoStructure library to access `account.photostructure.com`.

<a id="rpi-install"></a>

[Raspberry Pi installation instructions have been moved here](/server/photostructure-for-rpi/).

