{"id":13602743,"url":"https://github.com/finom/node-direct","last_synced_at":"2025-04-07T08:32:22.563Z","repository":{"id":142323739,"uuid":"68230368","full_name":"finom/node-direct","owner":"finom","description":"Allows to run server-side JavaScript files via NodeJS as easy as PHP files via Apache","archived":false,"fork":false,"pushed_at":"2018-04-09T20:11:35.000Z","size":110,"stargazers_count":98,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-22T15:22:51.381Z","etag":null,"topics":["javascript","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/finom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-09-14T18:01:33.000Z","updated_at":"2020-06-23T12:23:07.000Z","dependencies_parsed_at":"2024-01-16T22:52:57.388Z","dependency_job_id":null,"html_url":"https://github.com/finom/node-direct","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finom%2Fnode-direct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finom%2Fnode-direct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finom%2Fnode-direct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/finom%2Fnode-direct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/finom","download_url":"https://codeload.github.com/finom/node-direct/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247620398,"owners_count":20968202,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","nodejs"],"created_at":"2024-08-01T18:01:36.648Z","updated_at":"2025-04-07T08:32:22.139Z","avatar_url":"https://github.com/finom.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# node-direct [![npm version](https://badge.fury.io/js/node-direct.svg)](https://badge.fury.io/js/node-direct) [![Build Status](https://travis-ci.org/finom/node-direct.svg?branch=master)](https://travis-ci.org/finom/node-direct)\n\n\u003e Run server-side JavaScript files directly\n\nIf your VPS contains a lot of applications and you don't want to set up NodeJS server for every application, you're in the right place. **node-direct** allows to run JavaScript on a server just like **.php** files are run. The tool initializes one NodeJS instance per many websites and executes JavaScript files when URLs like **example.com/foo/bar.srv.js** are requested. **.srv.js** extension is configurable.\n\nYou know how to set up and run PHP script. You just need to upload it and run like this: *example.com/foo.php*. But what about NodeJS? You must define routes, run every app on its own port, set up deployment, make sure that all instances work after server reload... It's OK if you do a big application but when you have only small server-side utilities (like ajax proxy) they just wasting your time.\n\nInstall:\n```sh\nnpm install -g node-direct\n```\n\n## Nginx configuration\n\nAll the magic mostly happens on Nginx side (the project itself is extremely small). You'll need to configure it to handle requests to **.srv.js** files.\n\n```nginx\nlocation ~ \\.srv\\.js$ {\n    root \u003cpath_to_website_files\u003e;\n    proxy_pass http://localhost:\u003cport\u003e;\n    proxy_set_header X-Requested-File-Path $document_root$uri;\n}\n```\n\n- ``path_to_website_files`` - where static files are located.\n- ``port`` - a port of node-direct server\n\nExample:\n```nginx\nserver {\n    listen 80;\n\n    server_name example.com;\n\n    # Serve static files\n    location / {\n        root /var/web/example.com/public;\n        index index.srv.js index.html index.htm;\n    }\n\n    location ~ \\.srv\\.js$ {\n        root /var/web/example.com/public;\n        proxy_pass http://localhost:8123;\n        proxy_set_header X-Requested-File-Path $document_root$uri;\n    }\n}\n```\n\n## Usage\n\n```sh\nnode-direct --port=8000\n```\n\n**node-direct** is powered by [Express](http://expressjs.com/). Every **.srv.js** file should export a function which accepts ``request`` and ``response`` objects created by Express.\n\nHello world:\n```js\nmodule.exports = function(req, res) {\n    const someModule = require('some-module');\n    res.send('Hello world!');\n}\n```\n\nJSON API:\n```js\nmodule.exports = function(req, res) {\n    if(req.method === 'POST') {\n        req.json({\n            message: 'Everything is awesome'\n        });\n    } else {\n        req.status(400).json({\n            message: 'Only POST requests are allowed'\n        });\n    }\n}\n```\n\nHTML rendering:\n```js\nconst fs = require('fs');\nconst ejs = require('ejs');\nconst template = ejs.compile(fs.readFileSync('./templates/index.html'));\n\nmodule.exports = function(req, res) {\n    res.type('html').send(template({ foo: 'bar' }));\n}\n```\n\nCheck out Express documentation for more info.\n\nYou can use local **package.json** and require any modules by **.srv.js** files placed at **node_modules** as you usually do. There is an example of potential file structure of an app.\n```\n/package.json - a package file with dependencies and devDependencies for this specific application\n/index.html - main HTML file\n/js/app.js - client-side JavaScript app\n/css/style.css - styles\n/node_modules/ - things installed by \"npm install\"\n/foo/index.srv.js - some JSON API which allows to make requests to /foo/\n/bar/index.srv.js - some dynamic HTML page returned when /bar/ is requested\n```\n\n### Flags\n#### Common\n- ``--port`` - a port of node-direct server (8123 by default)\n\n#### Standalone mode\nThe standalone mode creates static HTTP server which doesn't require Nginx for its work. It should be used for development purposes on your local machine.\n- ``--standalone`` - turns on standalone mode\n- ``--root`` - a root of static files (``process.cwd()`` by default)\n- ``--ext`` - an extension of runnable JS files (**.srv.js** by default)\n\n```sh\nnode-direct --port=8000 --standalone --root=./foo/bar --ext=.serverside.js\n```\n\n\n## Running node-direct on startup (Linux)\n\nYou can add cron job to run the server on startup. To modify crontab run ``crontab -e``. Add the job to the end of the crontab file:\n\n```\n@reboot \u003cpath_to_node\u003e \u003cpath_to_installed_module\u003e [\u003cflags\u003e]\n```\n\n- ``path_to_node`` - absolute path to NodeJS binary (run ``which node`` to get the path)\n- ``path_to_installed_module`` - absolute path to installed node-direct (there is no direct way to get it)\n- ``flags`` - flags you want to use\n\nExample:\n```\n@reboot /usr/local/bin/node /usr/local/lib/node_modules/node-direct/index.js --port=8123\n```\n\n(if you have examples how to set up startup script for another OS, feel free to make PR)\n\n## Troubleshooting\n\n### Automatic module reload\n\nAs you know NodeJS caches values returned by ``require`` function. When you call ``require('foo')`` twice or more it returns the same object. **node-direct** updates cache when **.srv.js** file is replaced (eg. you upload another version of such file) and you don't have to reload **node-direct** every time when the file is changed. A problem can appear there when you require other modules by **.srv.js** files.\n```js\n// foo.srv.js\nmodule.exports = function(req, res) {\n    const bar = require('./bar');\n    // ...\n}\n```\n\nWhen you change **foo.srv.js** it is reloaded as expected but when you change **./bar** its value returned by ``require`` remains the same. The tool could hot-reload all requested modules but this would make side-effects which may cause unpredictable behavior in other modules. To handle this issue and update module cache you need to define watcher and clear cache when the ``require``'d file is changed.\n\nIn example below you do want to hot reload **./bar** when it's changed but you don't want to update **./baz** on its change.\n\n```js\n// foo.srv.js\n\n// for more modules you'll need to use a loop\nconst fs = require('fs');\nconst barPath = require.resolve('./bar');\nconst watcher = fs.watch(barPath, (eventType) =\u003e {\n    if (eventType === 'change') {\n        delete require.cache[barPath];\n        watcher.close();\n    }\n});\n\nmodule.exports = function(req, res) {\n    const bar = require('./bar');\n    const baz = require('./baz');\n    // ...\n}\n```\n\nIf it looks too tricky check out [fresh-up](https://github.com/finom/fresh-up).\n\n```js\n// foo.srv.js\n\n// for more modules you'll need to use a loop\nconst freshUp = require('fresh-up');\nfreshUp(require.resolve('./bar');\n\nmodule.exports = function(req, res) {\n    const bar = require('./bar');\n    const baz = require('./baz');\n    // ...\n}\n```\n\n\n### Potential vulnerability: ``X-Requested-File-Path`` header\n\nAs you may notice, Nginx config described above passes requested file path as ``X-Requested-File-Path`` HTTP header. A hacker can use this header to run custom JavaScript files on your server. The server needs to contain some dangerous JavaScript file and the hacker needs to know its path relative to root. If you want to fix this potential vulnerability you'll need to deny an access to a port used by node-direct with firewall.  \n\nThis is how it can be made on Linux:\n```\nsudo ufw deny 8123\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffinom%2Fnode-direct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffinom%2Fnode-direct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffinom%2Fnode-direct/lists"}