]> juplo.de Git - website/blob
a916f39bae36964ae7bf716c6b14b5d7ed9cd48a
[website] /
1 ---
2 _edit_last: "2"
3 author: kai
4 categories:
5   - howto
6   - java
7   - oauth2
8   - spring
9   - spring-boot
10 classic-editor-remember: classic-editor
11 date: "2020-11-10T07:20:07+00:00"
12 guid: http://juplo.de/?p=1037
13 parent_post_id: null
14 post_id: "1037"
15 title: 'How To Redirect To Spring Security OAuth2 Behind a Gateway/Proxy -- Part 2: Hiding The App Behind A Reverse-Proxy (Aka Gateway)'
16 url: /how-to-redirect-to-spring-security-oauth2-behind-a-gateway-proxy-hiding-the-app-behind-a-reverse-proxy-gateway/
17
18 ---
19 This post is part of a series of Mini-Howtos, that gather some help, to get you started, when switching from localhost to production with SSL and a reverse-proxy (aka gateway) in front of your app, that forwards the requests to your app that listens on a different name/IP, port and protocol.
20
21 ## In This Series We...
22
23 1. [Run the official Spring-Boot-OAuth2-Tutorial as a container in docker](/howto-redirect-to-spring-security-oauth2-behind-a-gateway-proxy-running-your-app-in-docker/)
24 1. Simulate production by hiding the app behind a gateway (this part)
25 1. Show how to debug the oauth2-flow for the whole crap!
26 1. Enable SSL on our gateway
27 1. Show how to do the same with Facebook, instead of GitHub
28
29 I will also give some advice for those of you, who are new to Docker - _but just enough to enable you to follow_.
30
31 This is **part 2** of this series, that shows how to **run a Spring-Boot OAuth2 App behind a gateway**
32 \- Part 1 is linked above.
33
34 ## Our Plan: Simulating A Production-Setup
35
36 We will simulate a production-setup by adding the domain, that will be used in production - `example.com` in our case -, as an alias for `localhost`.
37
38 Additionally, we will start an [NGINX](https://nginx.com) as reverse-proxy alongside our app and put both containers into a virtual network.
39 This simulates a real-world secenario, where your app will be running behinde a gateway together with a bunch of other apps and will have to deal with forwarded requests.
40
41 Together, this enables you to test the production-setup of your oauth2-provider against a locally running development environment, including the configuration of the finally used URIs and nasty forwarding-errors.
42
43 To reach this goal we will have to:
44
45 1. [Reconfigure our oauth-provider for the new domain](#provider-production-setup)
46 1. [Add the domain as an alias for localhost](#set-alias-for-domain)
47 1. [Create a virtual network](#create-virtual-network)
48 1. [Move the app into the created virtual network](#move-app-into-virtual-network)
49 1. [Configure and start nginx as gateway in the virtual network](#start-gateway-in-virtual-network)
50
51 _By the way:_
52 Any other server, that can act as reverse proxy, or some real gateway,like [Zuul](https://github.com/Netflix/zuul "In real real-world you should consider something like Zuul of similar") would work as well, but we stick with good old NGINX, to keep it simple.
53
54 ## Switching The Setup Of Your OAuth2-Provider To Production
55
56 In our example we are using GitHub as oauth2-provider and `example.com` as the domain, where the app should be found after the release.
57 So, we will have to change the **Authorization callback URL** to
58 **`http://example.de/login/oauth2/code/github`**
59
60 ![](/wp-uploads/2020/03/github-example.jpg)
61
62 O.k., that's done.
63
64 But we haven't released yet and nothing can be found on the reals server, that hosts `example.com`...
65 But still, we really would like to test that production-setup to be sure that we configured all bits and pieces correctly!
66
67 _In order to tackle this chicken-egg-problem, we will fool our locally running browser to belive, that `example.com` is our local development system._
68
69 ## Setting Up The Alias for `example.com`
70
71 On Linux/Unix this can be simply done by editing **`/etc/hosts`**.
72 You just have to add the domain ( `example.com`) at the end of the line that starts with `127.0.0.1`:
73
74 ```hosts
75 127.0.0.1       localhost example.com
76
77 ```
78
79 Locally running programms - like your browser - will now resolve `example.com` as `127.0.0.1`
80
81 ## Create A Virtual Network With Docker
82
83 Next, we have to create a virtual network, where we can put in both containers:
84
85 ```sh
86 docker network create juplo
87
88 ```
89
90 Yes, with Docker it is as simple as that.
91
92 Docker networks also come with some extra goodies.
93 Especially one, which is extremly handy for our use-case is: They are enabling automatic name-resolving for the connected containers.
94 Because of that, we do not need to know the IP-addresses of the participating containers, if we give each connected container a name.
95
96 ## Docker vs. Kubernetes vs. Docker-Compose
97
98 We are using Docker here on purpose.
99 Using Kubernetes just to test / experiment on a DevOp-box would be overkill.
100 Using Docker-Compose might be an option.
101 But we want to keep it as simple as possible for now, hence we stick with Docker.
102 Also, we are just experimenting here.
103
104 _You might want to switch to Docker-Compose later._
105 _Especially, if you plan to set up an environment, that you will frequently reuse for manual tests or such._
106
107 ## Move The App Into The Virtual Network
108
109 To move our app into the virtual network, we have to start it again with the additional parameter **`--network`**.
110 We also want to give it a name this time, by using **`--name`**, to be able to contact it by name.
111
112 _You have to stop and remove the old container from part 1 of this HowTo-series with `CTRL-C` beforehand, if it is still running - Removing is done automatically, because we specified `--rm`_:
113
114 ```sh
115 docker run \
116   -d \
117   --name app \
118   --rm \
119   --network juplo \
120   juplo/social-logout:0.0.1 \
121   --server.use-forward-headers=true \
122   --spring.security.oauth2.client.registration.github.client-id=YOUR_GITHUB_ID \
123   --spring.security.oauth2.client.registration.github.client-secret=YOUR_GITHUB_SECRET
124
125 ```
126
127 Summary of the changes in comparison to [the statement used in part 1](/howto-redirect-to-spring-security-oauth2-behind-a-gateway-proxy-running-your-app-in-docker/#build-a-docker-image "Skip back to part 1, if you want to compare..."):
128
129 - We added **`-d`** to run the container in the background - _See tips below..._
130 - We added **`--server.use-forward-headers=true`**, which is needed, because our app is running behind a gateway now - _I will explain this in more detail later_
131 - _And:_ Do not forget the **`--network juplo`**,
132   which is necessary to put the app in our virtual network `juplo`, and **`--name app`**, which is necessary to enable DNS-resolving.
133
134 - You do not need the port-mapping this time, because we will only talk to our app through the gateway.  
135
136   Remember: _We are **hiding** our app behind the gateway!_
137
138 ## Some quick tips to Docker-newbies
139
140 - Since we are starting multiple containers, that shall run in parallel, you have to start each command in a separate terminal, because **`CTRL-C`** will stop (and in our case remove) the container again.
141
142 - Alternatively, you can add the parameter **`-d`** (for daemonize) to start the container in the background.
143
144 - Then, you can look at its output with **`docker logs -f NAME`** (safely disruptable with `CTRL-C`) and stop (and in our case remove) the container with **`docker stop NAME`**.
145
146 - If you wonder, which containers are actually running, **`docker ps`** is your friend.
147
148 ## Starting the Reverse-Proxy Aka Gateway
149
150 Next, we will start NGINX alongside our app and configure it as reverse-proxy:
151
152 1. Create a file **`proxy.conf`** with the following content:
153
154    ```sh
155    upstream upstream_a {
156      server        app:8080;
157    }
158
159    server {
160      listen        80;
161      server_name   example.com;
162
163      proxy_set_header     X-Real-IP           $remote_addr;
164      proxy_set_header     X-Forwarded-For     $proxy_add_x_forwarded_for;
165      proxy_set_header     X-Forwarded-Proto   $scheme;
166      proxy_set_header     Host                $host;
167      proxy_set_header     X-Forwarded-Host    $host;
168      proxy_set_header     X-Forwarded-Port    $server_port;
169
170      location / {
171        proxy_pass  http://upstream_a;
172      }
173    }
174
175    ```
176
177    - We define a server, that listens to requests for the host **`example.com`** ( `server_name`) on port **`80`**.
178    - With the `location`-directive we tell this server, that all requests shall be handled by the upstream-server **`upstream_a`**.
179    - This server was defined in the `upstream`-block at the beginning of the configuration-file to be a forward to **`app:8080`**
180    - **`app`** is simply the name of the container, that is running our oauth2-app - Rembember: the name is resolvable via DNS
181    - **`8080`** is the port, our app listens on in that container.
182    - The `proxy_set_header`-directives are needed by Spring-Boot Security, for dealing correctly with the circumstance, that it is running behind a reverse-proxy.
183
184 _In part 3, we will survey the `proxy_set_header`-directives in more detail._
185 1. Start nginx in the virtual network and connect port `80` to `localhost`:
186
187    ```sh
188    docker run \
189      --name proxy \
190      --rm \
191      --network juplo -p 80:80 \
192      --volume $(pwd)/proxy.conf:/etc/nginx/conf.d/proxy.conf:ro \
193      nginx:1.17
194
195    ```
196
197    _This command has to be executed in the direcotry, where you have created the file `proxy.conf`._
198
199    - I use NGINX here, because I want to demystify the work of a gateway  
200 _[traefik](https://docs.traefik.io/ "Read more about this great tool") would have been easier to configure in this setup, but it would have disguised, what is going on behind the scene: with NGINX we have to configure all manually, which is more explicitly and hence, more informative_
201    - We can use port `80` on localhost, since the docker-daemon runs with root-privileges and hence, can use this privileged port - _if you do not have another webserver running locally there_.
202    - `$(pwd)` resolves to your current working-directory - This is the most convenient way to produce the absolute path to `proxy.conf`, that is required by `--volume` to work correclty.
203
204 If you have reproduced the receipt exacly, your app should be up and running now.
205 That is:
206
207    - Because we set the alias `example.com` to point at `localhost` you should now be able to open your app as **`http://example.com` in a locally running browser**
208    - You then should be able to login/logount without errors
209    - If you have configured everything correctly, neither your app nor GitHub should mutter at you during the redirect to GitHub and back to your app
210
211 ## Whats next... is what can go wrong!
212
213 In this simulated production-setup a lot of stuff can go wrong!
214 You may face nearly any problem from configuration-mismatches considering the redirect-URIs to nasty and hidden redirect-issues due to forwarded requests.
215
216 _Do not mutter at me..._
217 _**Remember:** That was the reason, we set up this simulated production-setup in the first place!_
218
219 In the next part of this series I will explain some of the most common problems in a production-setup with forwarded requests.
220 I will also show, how you can debug the oauth2-flow in your simulated production-setup, to discover and solve these problems