@@ -8,20 +8,21 @@ While this is simple, it has some trade-offs:
88- No way to test a new version while another is live (blue/green)
99- No quick rollback once upgraded
1010
11- When your app is ready for production, you can enable a traffic router to
12- eliminate these issues.
11+ When your app is ready for production, you can enable a simple ** traffic
12+ router ** to eliminate these issues.
1313
1414## 🧭 How It Works
1515
16- The traffic router is a lightweight proxy project ( already included with
17- SuperStack) that sits in front of your app. Its responsibilities:
16+ The traffic router is a lightweight proxy already included with SuperStack that
17+ sits in front of your app. Its responsibilities:
1818
19- - Route traffic to the active app stack
19+ - Route traffic to the correct app
2020- Simplify switching between versions
2121- Handle TLS termination
2222
2323``` mermaid
2424flowchart TD
25+ FormerApp["Former App"]
2526 Proxy["Traffic Router"]
2627 Proxy --> LiveApp["Live App"]
2728 NextApp["Next App"]
@@ -30,37 +31,42 @@ flowchart TD
3031Normally the app exposes ports directly, but in this advanced mode, the ** proxy
3132owns the ports** , and apps connect to its Docker network.
3233
33- ## 🔄 Deployment Flow
34+ ## 🔄 Tasks
3435
35- 1 . Enable the proxy project (included in the repository).
36- 1 . Stop exposing ports in the app — only the proxy will listen on ` :80 ` and
37- ` :443 ` .
38- 1 . For each deployment, bring up a new app stack (e.g. ` app/<commit> ` ),
39- connected to the proxy’s network.
40- 1 . Test the new app while the current one remains live.
41- 1 . Flip traffic in the proxy to point to the new app.
42- 1 . Tear down the old one when ready.
36+ 1 . Enable the proxy project (included in SuperStack)
37+ 1 . Stop exposing ports in the app
38+ 1 . Instead, connect to the proxy's Docker network
39+ 1 . The proxy will listen on ` :80 ` and ` :443 `
4340
44- ## 🧱 1. Start the Proxy
41+ The application still manages api routes, auth, etc.
4542
46- A ` proxy ` project already exists in your SuperStack project.
43+ ## 🧱 1. Start the Proxy
4744
4845> For consistent environments, use the proxy in all environments, including
4946> development.
5047
48+ A ` proxy ` project already exists in your SuperStack project.
49+
50+ First, stop your app to release the ports:
51+
52+ ``` sh
53+ cd app
54+ docker compose down
55+ ```
56+
5157Start the proxy:
5258
5359``` sh
54- cd proxy
60+ cd ../ proxy
5561docker compose up -d
5662```
5763
5864## ⚙️ 2. Adjust the Application
5965
60- ** Remove the ` ports: ` section from the app,** and connect it to the proxy's
61- network by adding these lines:
66+ ** Remove the ` ports: ` from the app,** and connect it to the proxy's network by
67+ adding these lines:
6268
63- ``` yaml title="app/compose.yaml" hl_lines="5-11 13- 15"
69+ ``` yaml title="app/compose.yaml" hl_lines="5-15"
6470services :
6571 caddy :
6672 build :
@@ -78,30 +84,41 @@ networks:
7884 external : true
7985` ` `
8086
81- You should also remove the ` ports:` and `CADDY_SITE_ADDRESS` in
87+ Also remove the ` ports:` and `CADDY_SITE_ADDRESS` in
8288` app/compose.override.yaml` .
8389
8490What's Changed?
8591
86- 1. Exposed ports were removed.
87- 1. `CADDY_SITE_ADDRESS` now listens internally on port `:80`.
88- 1. The app joins the proxy's network so traffic can be routed to it.
92+ 1. Exposed ports were removed
93+ 1. `CADDY_SITE_ADDRESS` now listens internally on port `:80`
94+ 1. The app joins the proxy's network so traffic can be routed to it
89951. A container alias (`_caddy`) allows the proxy to target this service
90- reliably.
96+ reliably
9197
92- Recreate the app's Caddy container :
98+ Bring up the app :
9399
94100` ` ` sh
95- cd app
96- docker compose up -d --force-recreate caddy
101+ docker compose up -d
102+ ` ` `
103+
104+ Test with :
105+
106+ ` ` ` sh
107+ $ curl http://localhost:8000/healthcheck
108+ OK
97109` ` `
98110
99111Commit these changes – your app is now proxy-ready.
100112
101- # # 🚀 3. Deploying
113+ # # 🚀 3. Deploying to a Remote Server
114+
115+ The proxy is deployed once (usually manually). After that, each app version is
116+ deployed separately into its own directory.
102117
103- The proxy is deployed once (usually manually), and each app is deployed
104- separately into its own directory.
118+ 1. For each deployment, bring up a new app (e.g. `app/<commit>`)
119+ 1. Test the new app while the current one remains live
120+ 1. Flip traffic in the proxy to point to the new app
121+ 1. Tear down the old one when ready
105122
106123```
107124proxy/
115132 .env
116133```
117134
135+ ### 1. Deploy the Proxy
136+
118137Before deploying, build and push your own proxy image by adding an `image:`
119138line to the Compose file:
120139
@@ -151,45 +170,93 @@ Start the proxy:
151170docker compose up -d
152171```
153172
154- ## 🆕 4 . Deploy the New App Stack
173+ ### 2 . Deploy a new App version
155174
156- Deploy your app into a new directory (e.g. ` b/ ` ):
175+ Deploy your app into a new directory (e.g. ` app/b/ ` ):
176+
177+ > Important: Give it a unique directory name every time. Here we use 'b' for
178+ > simplicity, but I recommend using the commit hash.
157179
158180``` sh
159181mkdir app/b
160182```
161183
184+ Copy ` compose.yaml ` (and secrets) there:
185+
162186``` sh
163187scp compose.yaml yourserver:app/b/
164188```
165189
166- Start it on the server:
190+ Start the app on the server:
167191
168192``` sh
169193cd app/b
170194docker compose up -d
171195```
172196
173- Optionally, verify the new app is healthy before switching traffic:
197+ Verify the new app is healthy before switching traffic:
174198
175199``` sh
176200$ docker compose exec -T caddy curl -fsS http://caddy:80/healthz
177201OK
178202```
179203
180- ## 🔁 5. Flip Traffic
204+ ## 🔁 4. Route Traffic
205+
206+ ### Option 1: Use the REST API
207+
208+ Caddy's configuration can be adjusted via HTTP using its [ REST
209+ API] ( https://caddyserver.com/docs/api ) .
210+
211+ Since the app was brought up in a directory named ` b ` , the app's Caddy service
212+ was given the alias ` b_caddy ` .
213+
214+ Direct all traffic to ` b_caddy ` :
181215
182216``` sh
183217cd proxy
184- docker compose exec caddy curl -X PATCH -d ' "newapp_caddy :80"' \
218+ docker compose exec caddy curl -X PATCH -d ' "b_caddy :80"' \
185219 http://localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/upstreams/0/dial
186220```
187221
188222Traffic now points to the new stack.
189223
224+ ### Option 2: Mount a Caddyfile
225+
226+ Create a simple Caddyfile on the server, such as:
227+
228+ ``` caddyfile title="proxy/caddy/Caddyfile"
229+ {$CADDY_SITE_ADDRESS}
230+
231+ reverse_proxy b_caddy:80
232+ ```
233+
234+ Mount it into the proxy's Caddy container:
235+
236+ ``` yaml title="proxy/compose.yaml" hl_lines="4"
237+ services :
238+ caddy :
239+ volumes :
240+ - ./caddy:/etc/caddy
241+ ` ` `
242+
243+ Recreate the container:
244+
245+ ` ` ` sh
246+ cd proxy
247+ docker compose up -d --force-recreate caddy
248+ ```
249+
250+ After that, to re-route traffic, simply change the app service name in
251+ ` proxy/caddy/Caddyfile ` and reload the proxy's configuration:
252+
253+ ``` sh
254+ docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
255+ ```
256+
190257## ⚡ GitHub Actions Example
191258
192- Use this Github Actions Workflow to automate deployments.
259+ Add this Github Actions workflow to automate deployments:
193260
194261<details >
195262<summary >Show full workflow</summary >
0 commit comments