content/blog/2022-04-02-nginx-reverse-proxy.org

0b2895a90c7751ce06e4b26d4db41005ea2f40a9
cleberg.net/content/blog/2022-04-02-nginx-reverse-proxy.org rendered · source · history · blame · raw

231 lines · 8091 bytes

  1#+date:        <2022-04-02 Sat 00:00:00>
  2#+title:       Configuration of Nginx as a Reverse Proxy Server on Ubuntu
  3#+description: Technical guide for setting up Nginx server to operate as a reverse proxy on Ubuntu systems, including configuration files setup and operational parameters.
  4#+slug:        nginx-reverse-proxy
  5#+filetags:    :nginx:reverse-proxy:ubuntu:
  6
  7* What is a Reverse Proxy?
  8
  9A reverse proxy is a server that is placed between local servers or
 10services and clients/users (e.g., the internet). The reverse proxy
 11intercepts all requests from clients at the network edge and uses its
 12configuration files to determine where each request should be sent.
 13
 14** A Brief Example
 15
 16For example, let's say that I run three servers in my home:
 17
 18- Server01 (=example.com=)
 19- Server02 (=service01.example.com=)
 20- Server03 (=service02.example.com=)
 21
 22I also run a reverse proxy in my home that intercepts all public
 23traffic:
 24
 25- Reverse Proxy
 26
 27Assume that I have a domain name (=example.com=) that allows clients to
 28request websites or services from my home servers.
 29
 30In this case, the reverse proxy will intercept all traffic from
 31=example.com= that enters my network and determine if the client is
 32requesting valid data, based on my configuration.
 33
 34If the user is requesting =example.com= and my configuration files say
 35that Server_{01} holds that data, Nginx will send the user to
 36Server_{01}. If I were to change the configuration so that =example.com=
 37is routed to Server_{02}, that same user would be sent to Server_{02}
 38instead.
 39
 40#+begin_src txt
 41┌──────┐                                              ┌───────────┐
 42│ User │─┐                                         ┌──► Server_01 │
 43└──────┘ │                                         │  └───────────┘
 44         │    ┌──────────┐   ┌───────────────┐     │  ┌───────────┐
 45         ├────► Internet ├───► Reverse Proxy ├─────├──► Server_02 │
 46         │    └──────────┘   └───────────────┘     │  └───────────┘
 47┌──────┐ │                                         │  ┌───────────┐
 48│ User │─┘                                         └──► Server_03 │
 49└──────┘                                              └───────────┘
 50#+end_src
 51
 52* Reverse Proxy Options
 53
 54There are a lot of options when it comes to reverse proxy servers, so
 55I'm just going to list a few of the options I've heard recommended over
 56the last few years:
 57
 58- [[https://nginx.com][Nginx]]
 59- [[https://caddyserver.com][Caddy]]
 60- [[https://traefik.io/][Traefik]]
 61- [[https://www.haproxy.org/][HAProxy]]
 62- [[https://ubuntu.com/server/docs/proxy-servers-squid][Squid]]
 63
 64In this post, we will be using Nginx as our reverse proxy, running on
 65Ubuntu Server 20.04.4 LTS.
 66
 67* Nginx Reverse Proxy Example
 68
 69** Local Applications
 70
 71You may be like me and have a lot of applications running on your local
 72network that you'd like to expose publicly with a domain.
 73
 74In my case, I have services running in multiple Docker containers within
 75a single server and want a way to visit those services from anywhere
 76with a URL. For example, on my local network,
 77[[https://dashy.to][Dashy]] runs through port 4000 (=localhost:4000=)
 78and [[https://github.com/louislam/uptime-kuma][Uptime Kuma]] runs
 79through port 3001 (=localhost:3001=).
 80
 81In order to expose these services to the public, I will need to do the
 82following:
 83
 841. Set up DNS records for a domain or subdomain (one per service) to
 85   point toward the IP address of the server.
 862. Open up the server network's HTTP and HTTPS ports (80 & 443) so that
 87   the reverse proxy can accept traffic and determine where to send it.
 883. Install the reverse proxy software.
 894. Configure the reverse proxy to recognize which service should get
 90   traffic from any of the domains or subdomains.
 91
 92** Step 1: DNS Configuration
 93
 94To start, update your DNS configuration so that you have an =A= record
 95for each domain or subdomain.
 96
 97The =A= records should point toward the public IP address of the server.
 98If you don't know the public IP address, log in to the server and run
 99the following command:
100
101#+begin_src sh
102curl ifconfig.co
103#+end_src
104
105In the DNS example below, =xxx.xxx.xxx.xxx= is the public IP address of
106the server.
107
108#+begin_src conf
109example.com             A        xxx.xxx.xxx.xxx
110uptime.example.com      A        xxx.xxx.xxx.xxx
111dashy.example.com       A        xxx.xxx.xxx.xxx
112www                     CNAME    example.com
113#+end_src
114
115Finally, ensure the DNS has propagated correctly with
116[[https://dnschecker.org][DNS Checker]] by entering your domains or
117subdomains in the search box and ensuring the results are showing the
118correct IP address.
119
120** Step 2: Open Network Ports
121
122This step will be different depending on which router you have in your
123home. If you're not sure, try to visit
124[[http://192.168.1.1][192.168.1.1]] in your browser. Login credentials
125are usually written on a sticker somewhere on your modem/router.
126
127Once you're able to log in to your router, find the Port Forwarding
128settings. You will need to forward ports =80= and =443= to whichever
129machine is running the reverse proxy.
130
131In my case, the table below shows the port-forwarding rules I've
132created. In this table, =xxx.xxx.xxx.xxx= is the local device IP of the
133reverse proxy server, it will probably be an IP between =192.168.1.1=
134and =192.168.1.255=.
135
136| NAME  | FROM PORT | DEST PORT/IP    | ENABLED |
137|-------+-----------+-----------------+---------|
138| HTTP  | 80        | xxx.xxx.xxx.xxx | TRUE    |
139| HTTPS | 443       | xxx.xxx.xxx.xxx | TRUE    |
140
141Once configured, these rules will direct all web traffic to your reverse
142proxy.
143
144** Step 3: Nginx Installation
145
146To install Nginx, simply run the following command:
147
148#+begin_src sh
149sudo apt install nginx
150#+end_src
151
152If you have a firewall enabled, open up ports =80= and =443= on your
153server so that Nginx can accept web traffic from the router.
154
155For example, if you want to use =ufw= for web traffic and SSH, run the
156following commands:
157
158#+begin_src sh
159sudo ufw allow 'Nginx Full'
160sudo ufw allow SSH
161sudo ufw enable
162#+end_src
163
164** Step 4: Nginx Configuration
165
166Now that we have domains pointing toward the server, the only step left
167is to configure the reverse proxy to direct traffic from domains to
168local services.
169
170To start, you'll need to create a configuration file for each domain in
171=/etc/nginx/sites-available/=. They will look identical except for the
172=server_name= variable and the =proxy_pass= port.
173
174Dashy:
175
176#+begin_src sh
177nano /etc/nginx/sites-available/dashy.example.com
178#+end_src
179
180#+begin_src config
181server {
182    listen 80;
183    server_name dashy.example.com;
184
185    location / {
186        proxy_pass http://localhost:4000;
187    }
188}
189#+end_src
190
191Uptime:
192
193#+begin_src sh
194nano /etc/nginx/sites-available/uptime.example.com
195#+end_src
196
197#+begin_src config
198server {
199    listen 80;
200    server_name uptime.example.com;
201
202    location / {
203        proxy_pass http://localhost:3001;
204    }
205}
206#+end_src
207
208Once the configuration files are created, you will need to enable them
209with the =symlink= command:
210
211#+begin_src sh
212sudo ln -s /etc/nginx/sites-available/dashy.example.com /etc/nginx/sites-enabled/
213#+end_src
214
215Voilà! Your local services should now be available through their URLs.
216
217* HTTPS with Certbot
218
219If you've followed along, you'll notice that your services are only
220available via HTTP (not HTTPS).
221
222If you want to enable HTTPS for your new domains, you will need to
223generate SSL/TLS certificates for them. The easiest way to generate
224certificates on Nginx is [[https://certbot.eff.org][Certbot]]:
225
226#+begin_src sh
227sudo apt install snapd; sudo snap install core; sudo snap refresh core
228sudo snap install --classic certbot
229sudo ln -s /snap/bin/certbot /usr/bin/certbot
230sudo certbot --nginx
231#+end_src