{"id":14978573,"url":"https://github.com/apostrophecms/mechanic","last_synced_at":"2025-04-08T03:09:40.127Z","repository":{"id":27335271,"uuid":"30809946","full_name":"apostrophecms/mechanic","owner":"apostrophecms","description":"Command-line tool to manage nginx-powered proxies for node apps. Static file delivery, load balancing, HTTPS, all that jazz with a clean interface.","archived":false,"fork":false,"pushed_at":"2022-03-26T09:48:08.000Z","size":487,"stargazers_count":169,"open_issues_count":6,"forks_count":26,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-03-31T13:16:36.665Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apostrophecms.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-14T21:53:53.000Z","updated_at":"2025-01-19T19:06:33.000Z","dependencies_parsed_at":"2022-09-26T20:41:18.594Z","dependency_job_id":null,"html_url":"https://github.com/apostrophecms/mechanic","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fmechanic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fmechanic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fmechanic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fmechanic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apostrophecms","download_url":"https://codeload.github.com/apostrophecms/mechanic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247767234,"owners_count":20992547,"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":[],"created_at":"2024-09-24T13:57:56.412Z","updated_at":"2025-04-08T03:09:40.099Z","avatar_url":"https://github.com/apostrophecms.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CircleCI](https://circleci.com/gh/apostrophecms/mechanic/tree/master.svg?style=svg)](https://circleci.com/gh/apostrophecms/mechanic/tree/master)\n\n# mechanic\n\n## Purpose\n\n[nginx](http://nginx.org) is a popular reverse proxy server among node developers. It's common to set up one or more node apps listening on high-numbered ports and use nginx virtual hosting and reverse proxy features to pass traffic to node. nginx can also serve static files better than node can, and it has battle-tested round-robin load balancing features.\n\nWe've boiled down our favorite configuration recipes for nginx to a simple utility that takes care of spinning up and shutting down proxies for new node sites on a server. It can also handle load balancing, canonical redirects, direct delivery of static files and https configuration. It takes the place of manually editing nginx configuration files.\n\n## Install\n\n**Step One:** install `nginx` on your Linux server.\n\nUnder Ubuntu Linux that would be:\n\n```\napt-get install nginx\n```\n\nMake sure Apache isn't in the way, already listening on port 80. Remove it really, really thoroughly. Or reconfigure it for an alternate port, like 9898, and set it up as a fallback as described below.\n\n**Step Two:**\n\n```\nnpm install -g mechanic\n```\n\nNOTE: `mechanic` will reconfigure nginx after each command given to it. A strong effort is made not to mess up other uses of nginx. Mechanic's nginx configuration output is written to `/etc/nginx/conf.d/mechanic.conf`, where both Debian-flavored and Red Hat-flavored Linux will load it. No other nginx configuration files are touched. You can change the folder where `mechanic.conf` is written, see below.\n\n**Step Three:**\n\nGo nuts.\n\nLet's add a single proxy that talks to one node process, which is listening on port 3000 on the same server (`localhost`):\n\n_All commands must be run as root._\n\n## Adding a site\n\n```\nmechanic add mysite --host=mysite.com --backends=3000\n```\n\nReplace `mysite` with a good \"shortname\" for _your_ site— letters and numbers and underscores only, no leading digits.\n\n`mechanic` will reconfigure and restart `nginx` as you go along and remember everything you've asked it to include.\n\n## Aliases: alternate hostnames\n\nNext we decide we want some aliases: other hostnames that deliver the same content. It's common to do this in the pre-launch period. With the `update` command we can add new options to a site without starting from scratch:\n\n```\nmechanic update mysite --aliases=www.mysite.com,mysite.temporary.com\n```\n\n## Canonicalization: redirecting to the \"real name\"\n\nIn production, it's better to redirect traffic so that everyone sees the same domain. Let's start redirecting from our aliases rather than keeping them in the address bar:\n\n```\nmechanic update mysite --canonical=true\n```\n\n## Setting a default site\n\nWe've realized this site should be the default site for the entire server. If a request arrives with a hostname that doesn't match any `--host` or `--aliases` list, it should always go to this site, redirecting first if the site is canonical. We can do that with `default`:\n\n```\nmechanic update mysite --default=true\n```\n\n**Warning:** If your server came with a default website already configured,\nlike the `server` block that appears in `/etc/nginx/nginx.conf` in\nCentOS 7, you will need to comment that out to use this feature. `mechanic`\ndoes not mess with the rest of your nginx settings, that is up to you.\n\n## Fast static file delivery\n\nLet's score a big performance win by serving our static files directly with nginx. This is simple: if a file matching the URL exists, nginx will serve it directly. Otherwise the request is still sent to node. All we have to do is tell nginx where our static files live.\n\n```\nmechanic update mysite --static=/opt/stagecoach/apps/mysite/current/public\n```\n\n_Browsers will cache the static files for up to 7 days. That's a good thing, but if you use this feature make sure any dynamically generated files have new filenames on each new deployment._\n\n## Serving `index.html` for bare directories\n\nWhen using `--static`, you can optionally enable serving `index.html` automatically when a URL matches a directory name by using the `--autoindex` option.\n\n```\nmechanic update mysite --autoindex\n```\n\nAs with all boolean options you can change your mind later:\n\n```\nmechanic update mysite --autoindex=false\n```\n\nIn a typical proxy configuration, this makes it possible to use an `index.html` file as a cached static version of a resource with a \"pretty URL\" like `/people` that would normally hit your back end server.\n\n## Static websites\n\nAlthough static websites will never be a primary use case for `mechanic`, you can set up a perfectly reasonable static webserver like this:\n\n```\nmechanic add mysite --host=mysite.com --static=/var/www/html/mysite --autoindex\n```\n\n**The `backends` option is no longer mandatory when `--static` is present.**\n\nIf you have more elaborate use cases that don't involve a reverse proxy, you should really create a separate nginx configuration file for that site.\n\n## Load balancing\n\nTraffic is surging, so we've set up four node processes to take advantage of four cores. They are listening on ports 3000, 3001, 3002 and 3003. Let's tell nginx to distribute traffic to all of them:\n\n```\nmechanic update mysite --backends=3000,3001,3002,3003\n```\n\n### Across two servers\n\nThis time we want to load-balance between two separate back-end servers, each of which is listening on two ports:\n\n```\nmechanic update mysite --backends=192.168.1.2:3000,192.168.1.2:3001,192.168.1.3:3000,192.168.1.3:3001\n```\n\n_You can use hostnames too._\n\n### Secure backends\n\nIf you're proxying to a remote server, it's a good idea to enable HTTPS there too, so your connection is secure end-to-end. If you use the `https-upstream` option, nginx will make requests to your backends using SSL.\n\n```\nmechanic update mysite --https-upstream\n```\n\nNote that this can introduce a significant performance overhead, as nginx will need to validate certificates and encrypt the connection with the backend.\n\n### Backends for certain URL paths only\n\nYou can configure a backend exclusively for with a certain path prefix:\n\n```\nmechanic update mysite --backends=3000,3001:/ci-server\n```\n\nThis is also supported for backends not running on the same computer:\n\n```\nmechanic update mysite --backends=192.168.1.2:3000,192.168.1.2:4000/ci-server\n```\n\nThe prefix **is included** in the URL passed through to the backend.\n\nIf such a backend is present, matching requests are sent only to it. You may have more than one for the same path, in which case they are load balanced by nginx in the usual way.\n\nThis feature is useful when microservices share a single hostname.\n\n## Secure sites\n\nNow we've added ecommerce and we need a secure site:\n\n```\nmechanic update mysite --https=true\n```\n\nNow nginx will serve the site with `https` (as well as `http`) and look for `mysite.cer` and `mysite.key` in the folder `/etc/nginx/certs`.\n\n[See the nginx docs on how to handle intermediate certificates.](http://nginx.org/en/docs/http/configuring_https_servers.html)\n\n## Redirecting to the secure site\n\nNext we decide we want the site to be secure all the time, redirecting any traffic that arrives at the insecure site:\n\n```\nmechanic update mysite --https=true --redirect-to-https=true\n```\n\n## Redirecting to another site\n\nWe can also redirect all traffic to a different site. To redirect 100% of the traffic to one specific URL, use `--redirect`:\n\n```\nmechanic update mysite --redirect=https://example.com\n```\n\nTo instead append the rest of the original URL to a redirected domain, use `--redirect-full`:\n\n```\nmechanic update mysite --redirect-full=https://example.com\n```\n\nSetting `--redirect` clears `--redirect-full`, and vice versa.\n\n## Enabling HTTP/2\n\nWe can enable HTTP/2 by setting http2 to true:\n\n```\nmechanic set true\n```\n\n## Disabling HTTP/2\n\nWe can disable HTTP/2 by setting http2 to an empty string:\n\n```\nmechanic set ''\n```\n\n## Permanent and Temporary Redirects\n\nAll redirects are temporary by default. To make redirects permanent (301), use `--permanent=true`. To go back to a temporary (302) redirect, use `--permanent=false`.\n\n```\nmechanic update mysite --permanent=true\n```\n\n## Shutting off HTTPS\n\nNow we've decided we don't want ecommerce anymore. Let's shut that off:\n\n```\nmechanic update mysite --https=false\n```\n\n## Removing a site\n\nNow let's remove the site completely:\n\n```\nmechanic remove mysite\n```\n\n## Disabling options\n\nYou can disable any previously set option, such as `static`, by setting it to `false` or the empty string.\n\n## Falling back to Apache\n\nIf you also want to serve some content with Apache on the same server, first configure Apache to listen on port `9898` instead of `80`, then set up a default site for `mechanic` that forwards traffic there:\n\n```javascript\nmechanic add apache --host=dummy --backends=9898 --default=true\n```\n\nWe still need a `host` setting even for a default site (TODO: remove this requirement).\n\nApache doesn't have to be your default. You could also use `--host` and set up individual sites to be forwarded to Apache.\n\n## Global options\n\nThere are a few global options you might want to change. Here's how. The values shown are the defaults.\n\n### conf: nginx configuration file location\n\n```javascript\nmechanic set conf /etc/nginx/conf.d\n```\n\nThis is the folder where the `mechanic.conf` nginx configuration file\nwill be created. Note that both Red Hat and Debian-flavored Linux\nload everything in this folder by default.\n\n### restart: nginx restart command\n\n```javascript\nmechanic set restart \"nginx -s reload\"\n```\n\nThe command to restart `nginx`.\n\n_Don't forget the quotes if spaces are present._ That's just how the shell works, but it bears repeating.\n\n### logs: webserver log file folder\n\n```javascript\nmechanic set logs /var/log/nginx\n```\n\nIf this isn't where you want your nginx access and error log files for\neach site, change the setting.\n\n### bind: bind address\n\n```javascript\nmechanic set bind \"*\"\n```\n\nBy default, `mechanic` tells nginx to accept traffic on all IP addresses assigned to the server. (`*` means \"everything.\") If this isn't what you want, set a specific ip address with `bind`.\n\n_If you reset this setting to `_` make sure you quote it, so the shell doesn't give you a list of filenames.\\*\n\n### Enabling websockets\n\nBy default, nginx does not proxy websockets. You can enable this by passing the `--websockets` flag:\n\n```\nmechanic update mysite --websockets\n```\n\nThis [enables websockets proxying per the nginx documentation](http://nginx.org/en/docs/http/websocket.html) by setting the HTTP version for the proxy to 1.1 and setting the Upgrade header.\n\nAs with other boolean flags you can turn this off again with `--websockets=false`.\n\n### template: custom nginx template file\n\n```javascript\nmechanic set template /etc/mechanic/custom.conf\n```\n\nYou don't have to use our nginx configuration template.\n\nTake a look at the file `template.conf` in the `nginx` npm module. It's just a [nunjucks](http://mozilla.github.io/nunjucks/) template that builds an `nginx` configuration based on your `mechanic` settings.\n\nYou can copy that template anywhere you like, make your own modifications, then use `mechanic set template` to tell `mechanic` where to find it.\n\n### Lazy overrides\n\nIf you don't want to customize our template, check out the convenience override files that `mechanic` creates for you:\n\n```\n/etc/nginx/mechanic-overrides/myshortname/top\n/etc/nginx/mechanic-overrides/myshortname/server\n/etc/nginx/mechanic-overrides/myshortname/location\n/etc/nginx/mechanic-overrides/myshortname/proxy\n```\n\n`top` is loaded before any of mechanic's directives for that site. Use it when nothing else fits.\n\n`server` is included inside the `server` block for the site, just before the `location` block, when `redirect-to-https` is not in effect. It is a good place to change a setting like `access_log`.\n\n`location` is included inside the `location` block, and is a good place to add something like CORS headers for static font files. It is also a good place to change the `client_max_body_size` directive.\n\n`proxy` is loaded inside the proxy server configuration and is ideal if you need to override mechanic's proxy settings.\n\nThese files start out empty; you can add whatever you like.\n\nOf course, if this isn't enough flexibility for your needs, you can create a custom template.\n\n## Refreshing your nginx configuration\n\nMaybe you updated mechanic with `npm update -g mechanic` and you want our\nlatest configuration. Maybe you edited your custom template. Either way,\nyou want to rebuild your nginx configuration without changing any\nsettings:\n\n```\nmechanic refresh\n```\n\n## Resetting to the defaults\n\nTo completely reset mechanic, throwing away everything it knows:\n\n```javascript\nmechanic reset\n```\n\n_Warning:_ like it says, this will completely reset your configuration and forget everything you've done. Don't do that unless you really want to.\n\n## Listing your configuration settings\n\n`mechanic list`\n\nThis gives you back commands sufficient to set them up the same way again. Great for copying to another server. Here's some sample output:\n\n```\nmechanic set restart \"/usr/sbin/nginx -s reload\"\nmechanic add test --host=test.com --aliases=www.test.com --canonical=true --https=true\nmechanic add test2 --host=test2.com --aliases=www.test2.com,test2-prelaunch.mycompany.com\n```\n\nIf you want to wipe the configuration on another server before applying these commands there, use `mechanic reset`.\n\n## Custom nginx templates\n\nYou don't have to use our nginx configuration template.\n\nTake a look at the file `template.conf` in the `nginx` npm module. It's just a [nunjucks](http://mozilla.github.io/nunjucks/) template that builds an `nginx` configuration based on your `mechanic` settings.\n\n## Custom nginx path\n\nIf you use brew (a package manager for mac) to install nginx, nginx install path will be `/usr/local/etc/nginx`.\nMechanic default nginx path is `/etc/nginx`.\nYou can change default nginx path below:\n\n```\nmechanic set restart 'brew services restart nginx'\nmechanic set conf '/usr/local/etc/nginx/conf.d'\nmechanic set overrides /usr/local/etc/nginx/mechanic-overrides\nmechanic set logs /usr/local/var/log/nginx\n```\n\n## Storing the database in a different place\n\nIt's stored in `/var/lib/misc/mechanic.json`. That's [one hundred percent correct according to the filesystem hierarchy standard](http://www.pathname.com/fhs/pub/fhs-2.3.pdf), adhered to by all major Linux distributions and many other flavors of Unix. But if you absolutely insist, you can use the `--data` option to specify another location. You'll have to do it every time you run `mechanic`, though. That's why we only use this option for unit tests.\n\nIf necessary `mechanic` will create `/var/lib/misc`.\n\n## Credits\n\n`mechanic` was created to facilitate our work at [P'unk Avenue](http://punkave.com). We use it to host sites powered by [ApostropheCMS](https://apostrophecms.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostrophecms%2Fmechanic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapostrophecms%2Fmechanic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostrophecms%2Fmechanic/lists"}