UNPKG

6.96 kBMarkdownView Raw
1<h1 align="center">Fastify</h1>
2
3## Recommendations
4
5This document contains a set recommendations, or best practices, when using
6Fastify.
7
8* [Use A Reverse Proxy](#reverseproxy)
9
10## Use A Reverse Proxy
11<a id="reverseproxy"></a>
12
13Node.js is an early adopter of frameworks shipping with an easy to use web
14server within the standard library. Previously, with languages like PHP or
15Python, one would need either a web server with specific support for the
16language or the ability to setup some sort of [CGI gateway][cgi] that works
17with the language. With Node.js, one can simply write an application that
18_directly_ handles HTTP requests. As a result, the temptation is to write
19applications that handle requests for multiple domains, listen on multiple
20ports (i.e. HTTP _and_ HTTPS), and various other scenarios and combinations
21thereof. Further, the temptation is to then expose these applications directly
22to the Internet to handle requests.
23
24The Fastify team **strongly** considers this to be an anti-pattern and extremely
25bad practice:
26
271. It adds unnecessary complexity to the application by diluting its focus.
282. It prevents [horizontal scalability][scale-horiz].
29
30See [Why should I use a Reverse Proxy if Node.js is Production Ready?][why-use]
31for a more thorough discussion of why one should opt to use a reverse proxy.
32
33For a concrete example, consider the situation where:
34
351. The app needs multiple instances to handle load.
361. The app needs TLS termination.
371. The app needs to redirect HTTP requests to HTTPS.
381. The app needs to serve multiple domains.
391. The app needs to serve static resources, e.g. jpeg files.
40
41There are many reverse proxy solutions available, and your environment may
42dictate the solution to use, e.g. AWS or GCP. But given the above, we could use
43[HAProxy][haproxy] to solve these requirements:
44
45```conf
46# The global section defines base HAProxy (engine) instance configuration.
47global
48 log /dev/log syslog
49 maxconn 4096
50 chroot /var/lib/haproxy
51 user haproxy
52 group haproxy
53
54 # Set some baseline TLS options.
55 tune.ssl.default-dh-param 2048
56 ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
57 ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
58 ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11
59 ssl-default-server-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
60
61# Each defaults section defines options that will apply to each subsequent
62# subsection until another defaults section is encountered.
63defaults
64 log global
65 mode http
66 option httplog
67 option dontlognull
68 retries 3
69 option redispatch
70 # The following option make haproxy close connections to backend servers
71 # instead of keeping them open. This can alleviate unexpected connection
72 # reset errors in the Node process.
73 option http-server-close
74 maxconn 2000
75 timeout connect 5000
76 timeout client 50000
77 timeout server 50000
78
79 # Enable content compression for specific content types.
80 compression algo gzip
81 compression type text/html text/plain text/css application/javascript
82
83# A "frontend" section defines a public listener, i.e. an "http server"
84# as far as clients are concerned.
85frontend proxy
86 # The IP address here would be the _public_ IP address of the server.
87 # Here, we use a private address as an example.
88 bind 10.0.0.10:80
89 # This redirect rule will redirect all traffic that is not TLS traffic
90 # to the same incoming request URL on the HTTPS port.
91 redirect scheme https code 308 if !{ ssl_fc }
92 # Technically this use_backend directive is useless since we are simply
93 # redirecting all traffic to this frontend to the HTTPS frontend. It is
94 # merely included here for completeness sake.
95 use_backend default-server
96
97# This frontend defines our primary, TLS only, listener. It is here where
98# we will define the TLS certificates to expose and how to direct incoming
99# requests.
100frontend proxy-ssl
101 # The `/etc/haproxy/certs` directory in this example contains a set of
102 # certificate PEM files that are named for the domains the certificates are
103 # issued for. When HAProxy starts, it will read this directory, load all of
104 # the certificates it finds here, and use SNI matching to apply the correct
105 # certificate to the connection.
106 bind 10.0.0.10:443 ssl crt /etc/haproxy/certs
107
108 # Here we define rule pairs to handle static resources. Any incoming request
109 # that has a path starting with `/static`, e.g.
110 # `https://one.example.com/static/foo.jpeg`, will be redirected to the
111 # static resources server.
112 acl is_static path -i -m beg /static
113 use_backend static-backend if is_static
114
115 # Here we define rule pairs to direct requests to appropriate Node.js
116 # servers based on the requested domain. The `acl` line is used to match
117 # the incoming hostname and define a boolean indicating if it is a match.
118 # The `use_backend` line is used to direct the traffic if the boolean is
119 # true.
120 acl example1 hdr_sub(Host) one.example.com
121 use_backend example1-backend if example1
122
123 acl example2 hdr_sub(Host) two.example.com
124 use_backend example2-backend if example2
125
126 # Finally, we have a fallback redirect if none of the requested hosts
127 # match the above rules.
128 default_backend default-server
129
130# A "backend" is used to tell HAProxy where to request information for the
131# proxied request. These sections are where we will define where our Node.js
132# apps live and any other servers for things like static assets.
133backend default-server
134 # In this example we are defaulting unmatched domain requests to a single
135 # backend server for all requests. Notice that the backend server does not
136 # have to be serving TLS requests. This is called "TLS termination": the TLS
137 # connection is "terminated" at the reverse proxy.
138 # It is possible to also proxy to backend servers that are themselves serving
139 # requests over TLS, but that is outside the scope of this example.
140 server server1 10.10.10.2:80
141
142# This backend configuration will serve requests for `https://one.example.com`
143# by proxying requests to three backend servers in a round-robin manner.
144backend example1-backend
145 server example1-1 10.10.11.2:80
146 server example1-2 10.10.11.2:80
147 server example2-2 10.10.11.3:80
148
149# This one serves requests for `https://two.example.com`
150backend example2-backend
151 server example2-1 10.10.12.2:80
152 server example2-2 10.10.12.2:80
153 server example2-3 10.10.12.3:80
154
155# This backend handles the static resources requests.
156backend static-backend
157 server static-server1 10.10.9.2:80
158```
159
160[cgi]: https://en.wikipedia.org/wiki/Common_Gateway_Interface
161[scale-horiz]: https://en.wikipedia.org/wiki/Scalability#Horizontal
162[why-use]: https://web.archive.org/web/20190821102906/https://medium.com/intrinsic/why-should-i-use-a-reverse-proxy-if-node-js-is-production-ready-5a079408b2ca
163[haproxy]: https://www.haproxy.org/