Skip to content

SnapTeX Server ​

SnapTeX Server is an independent Node.js service. The editor shell, local folders, imported workspaces, and demo remain public. Only remote project access requires authentication.

Use this edition only when project files must stay on the server. For GitHub Pages or local/browser-managed projects, follow Static Web and PWA instead.

Requirements ​

  • Linux with Node.js 22 or later, npm, bash, curl, systemd, Nginx, and Certbot;
  • the acl package and permission to create a system service account;
  • a SnapTeX source checkout or source package from the deployment command below;
  • a projects directory whose direct children are named LaTeX projects;
  • a dedicated HTTPS origin such as https://snaptex.example.com.
  • for PDF compilation, either latexmk or Rscript with the R package tinytex. SyncTeX queries run locally in the browser and do not require the synctex CLI on the server.

Configure ​

bash
git clone https://github.com/qianchd/SnapTeX.git
cd SnapTeX
cp apps/web/server.env.example apps/web/server.env

Edit the private configuration:

dotenv
SNAPTEX_PROJECTS_ROOT=/srv/snaptex/projects
SNAPTEX_INSTALL_DIR=/opt/snaptex-web
SNAPTEX_SERVICE_NAME=snaptex-web
SNAPTEX_RUN_USER=snaptex
HOST=localhost
PORT=3000
SNAPTEX_AUTH_USERNAME=snaptex-admin
SNAPTEX_AUTH_PASSWORD=replace-with-a-long-random-password
SNAPTEX_PUBLIC_ORIGIN=https://snaptex.example.com
SNAPTEX_PUBLIC_PATH=/

SNAPTEX_PUBLIC_ORIGIN is an HTTPS origin without a path. Keep HOST on loopback and expose the service only through HTTPS.

VariablePurpose
SNAPTEX_PROJECTS_ROOTParent directory whose direct children are remotely openable project names.
SNAPTEX_INSTALL_DIRInstaller-managed runtime directory; do not point it at the source checkout.
SNAPTEX_SERVICE_NAMEsystemd unit name used by install, status, logs, and updates.
SNAPTEX_RUN_USERDedicated non-login OS account used by the service.
HOST / PORTLoopback listener consumed by Nginx. Keep HOST as localhost, 127.0.0.1, or ::1.
SNAPTEX_AUTH_USERNAME / SNAPTEX_AUTH_PASSWORDBuilt-in remote-project login. Use a unique username and a long random password.
SNAPTEX_PUBLIC_ORIGINExact public HTTPS origin used for origin and cookie checks, for example https://snaptex.example.com.
SNAPTEX_PUBLIC_PATHURL base path. Use / for the recommended dedicated-origin deployment.
SNAPTEX_RSCRIPTOptional path to Rscript when it is not on the service account's PATH.
SNAPTEX_PDF_COMPILERServer default: tinytex (default), latexmk, or auto. The web setting can override it per compilation; Auto probes Rscript with TinyTeX before direct latexmk.
SNAPTEX_LATEXMKOptional path to latexmk when it is not on the service account's PATH.

apps/web/server.env is ignored by Git. Protect the source checkout and configuration so only administrators can read the credentials.

Install ​

bash
npm run web:install-server

The installer:

  1. validates the private configuration;
  2. creates a non-login service account when necessary;
  3. grants scoped ACL access to the project tree;
  4. runs npm ci, builds the server edition, and runs server tests;
  5. validates and installs a hardened systemd unit;
  6. atomically switches the runtime and checks /healthz;
  7. restores the previous runtime if deployment fails.

For repeated development deployments from another machine, upload the current server build inputs and invoke the same installer with:

bash
npm run web:deploy-server -- <ssh-host> </absolute/remote/source-path>

The command packages tracked and non-ignored build inputs as a compressed .tar.gz, excluding README recordings, the documentation site, other hosts, and unrelated development tests/tools. It preserves the demo, bundled SyncTeX parser, and server deployment tests. It uses the local SSH configuration, preserves the ignored remote apps/web/server.env, and contains no credentials or deployment-specific addresses.

The production build minifies browser JavaScript and precompresses eligible text assets with Brotli and gzip. The Node service prefers Brotli, falls back to gzip, and serves the original file when neither encoding is accepted. It also supplies per-file ETags, 304 Not Modified responses, immutable caching for content-versioned URLs, and revalidation caching for HTML and service-worker.js. API, authentication, and project-file responses remain no-store.

After installation, systemctl status snaptex-web should show an active service and curl http://127.0.0.1:3000/healthz should return a successful health response. Replace the service name and port when your configuration differs.

Nginx and TLS ​

Copy the included virtual-host template and replace the example hostname and port:

bash
cp apps/web/deploy/nginx-site.conf /etc/nginx/sites-available/snaptex.example.com
ln -s /etc/nginx/sites-available/snaptex.example.com /etc/nginx/sites-enabled/snaptex.example.com
nginx -t && systemctl reload nginx
certbot --nginx -d snaptex.example.com

Nginx terminates TLS and proxies the complete origin to the loopback Node service. The application itself owns login, sessions, API authorization, and static assets.

Visit the public origin after Certbot completes. The welcome page, demo, local folder, and imported workspace remain public; Open Server asks for the configured credentials before exposing remote project names or files.

The default login lasts eight hours. Select Keep me signed in for 30 days only on a trusted device when a longer session is appropriate. Both modes use opaque, revocable server-side sessions; signing out invalidates the current session. Session state is kept in the systemd-managed state directory, so valid logins survive service restarts and atomic application updates without being stored in the release directory.

Project layout ​

If SNAPTEX_PROJECTS_ROOT=/srv/snaptex/projects, entering project name paper-one opens /srv/snaptex/projects/paper-one. Missing projects can be created after confirmation.

The API exposes only allowlisted project files and rejects hidden paths, traversal, symbolic-link escapes, unsupported writes, and files outside the selected project. Text-file responses include ETags, the manifest includes lightweight file revisions, and updates require If-Match so concurrent external edits cannot be overwritten by a stale browser save.

The Explorer lists project PDFs alongside text files. Click a PDF to view it in the preview panel; use TeX Preview to return. In a server project, File > Compile PDF or Ctrl+B saves the active edited file and compiles the current TeX root. Choose TinyTeX, direct latexmk, or Auto under Settings > PDF compiler; Auto probes TinyTeX first. If its generated PDF is already open, the preview refreshes after compilation; compilation does not open the PDF automatically. Other modified files must be saved first. Compilation failures open a dialog containing the compiler output.

PDFs with a same-name .synctex.gz or .synctex file support Ctrl+Alt+M from the editor to the PDF, double-clicking the PDF to locate its TeX source, and the existing Auto scroll sync setting. This works with local folders, imported workspaces, and server projects. Both files are loaded once when opening or refreshing the PDF; the bundled official SyncTeX parser performs queries in a browser Worker without contacting the server. Missing or invalid SyncTeX data does not prevent viewing the PDF. SyncTeX describes the last compilation, so recompile after editing to update its line mapping.

Server compilation refreshes an already open PDF and its SyncTeX index while retaining its PDF view location. External resource changes are delivered by the existing project file watcher. Local folders use FileSystemObserver when available, otherwise the existing five-second check while the tab is visible; unread binary files are not polled. Imported workspaces are snapshots and need re-importing to receive outside changes.

PDF/source queries remain available offline after the PDF, sidecar, and application assets have loaded. A server project's source file that has not yet been opened may still require a network read; importing the project into a browser workspace makes those source files available offline too. Closing the PDF releases the parser Worker and restores a full TeX preview load.

Compilation runs under the dedicated service account, not as root, with shell escape and automatic package installation disabled. Only give remote-project access to users trusted to submit TeX source: TeX compilation can still read files accessible to that account. Ctrl+B is intentionally limited to server projects; local and imported browser projects can open existing PDFs but cannot execute local programs.

Operate ​

bash
systemctl status snaptex-web
journalctl -u snaptex-web -f
curl http://127.0.0.1:3000/healthz

To update, pull or replace the source tree and rerun npm run web:install-server with the same private configuration.

If opening a project reports that the server cannot read it, inspect the concrete path with journalctl -u snaptex-web and rerun the installer to restore the configured project-tree ACLs. Do not bypass the service account by running SnapTeX as root.

Before upgrades, back up SNAPTEX_PROJECTS_ROOT independently. The installer rolls back application runtime failures, not user project content or administrator configuration mistakes.

See Security Model before exposing a deployment publicly.

Verify the public service ​

  1. Open the public origin and confirm local-only actions work without login.
  2. Choose Open Server, sign in, and open one allowlisted project by name.
  3. Save a synthetic text change, reload, and verify the server file changed.
  4. While the project is open, edit the same file on the server and verify the browser updates; then edit the same line on both sides and verify conflict markers appear.
  5. Confirm an invalid project name, hidden path, unsupported extension, and unauthenticated write are rejected.
  6. Compile a synthetic TeX root with Ctrl+B, click its PDF in Explorer, edit the TeX and compile again to verify the PDF preview refreshes.
  7. Review service logs and back up the project root before making the deployment available to other users.

A fast structural preview, not a replacement for a full TeX compiler.