@@ -8,19 +8,17 @@ 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, consider adding a ** traffic-switcher **
12- in front it .
11+ When your app is ready for production, you can enable a ** traffic-router ** in
12+ to eliminate downtime, enable blue/green testing and easy rollbacks .
1313
1414## 🧭 How It Works
1515
16- Instead of directly exposing ports from the app, you add a small proxy project
17- that sits in front of it.
16+ The traffic router is a lightweight proxy project (already included with
17+ SuperStack) that sits in front of your app. Its responsibilities:
1818
19- The proxy’s job is to:
20-
21- - Route incoming traffic to the active app stack
22- - Make it easy to flip traffic between app versions
23- - Terminate TLS
19+ - Route traffic to the active app stack
20+ - Simplify switching between versions
21+ - Handle TLS termination
2422
2523``` mermaid
2624flowchart TD
@@ -29,88 +27,36 @@ flowchart TD
2927 NextApp["Next App"]
3028```
3129
32- ## 🔄 Deployment Flow
33-
34- 1 . Stop exposing ports in the app project — only the proxy will listen on :80 and :443.
35- 2 . Add a proxy project that runs Caddy (or another gateway).
36- 3 . Each time you deploy, bring up a new app stack, connected to the proxy’s
37- network.
38- 4 . Test the new stack while the old one is still live.
39- 5 . Flip traffic in the proxy to point to the new stack.
40- 6 . Tear down the old one when ready.
41-
42- Ok, we need to make some changes to the repository.
30+ In standard mode, the app exposes ports directly. In advanced mode, the ** proxy
31+ owns the ports** , and apps connect to it internally over Docker networks.
4332
44- ## 1. Create a new ` proxy ` project
45-
46- From the root of the repository, create a new ` proxy ` project:
47-
48- ``` sh
49- mkdir proxy
50- ```
51-
52- Give it a Compose file:
53-
54- ``` yaml title="proxy/compose.yaml"
55- services :
56- caddy :
57- build :
58- context : ./caddy
59- ports :
60- - " 80:80"
61- - " 443:443"
62- volumes :
63- - caddy_data:/data
64- environment :
65- CADDY_SITE_ADDRESS : api.myapp.com
33+ ## 🔄 Deployment Flow
6634
67- volumes :
68- caddy_data :
69- name : caddy-data # Persistent volume for certificates
70- ` ` `
35+ 1 . Stop exposing ports in the app project — only the proxy will listen on ` :80 `
36+ and ` :443 ` .
37+ 1 . Enable the proxy project (included in the repository).
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.
7143
72- Add development overrides:
44+ ## 🧱 1. Start the Proxy
7345
74- ` ` ` yaml title="proxy/compose.override.yaml"
75- # Development overrides
46+ A ` proxy ` project already exists in your SuperStack project.
7647
77- services :
78- caddy :
79- ports :
80- - " 8000:80"
81- environment :
82- CADDY_SITE_ADDRESS : :80
83- ` ` `
48+ > For consistent environments, use the proxy in all environments including
49+ > development.
8450
85- Configure Caddy :
51+ Start it :
8652
8753``` sh
88- mkdir proxy/caddy
89- ```
90-
91- ``` yaml title="proxy/caddy/Caddyfile"
92- {$CADDY_SITE_ADDRESS}
93-
94- reverse_proxy app_caddy:80
95- ```
96-
97- Add a Dockerfile:
98-
99- ``` dockerfile title="proxy/caddy/Dockerfile"
100- FROM caddy:2
101-
102- COPY Caddyfile /etc/caddy/Caddyfile
103- ```
104-
105- Start the proxy service:
106-
107- ``` yaml
10854docker compose up -d
10955```
11056
111- ## 2. Adjust the Application
57+ ## ⚙️ 2. Adjust the Application
11258
113- Remove the app's exposed ports, and connect to the proxy's network:
59+ Remove the app's exposed ports and connect it to the proxy's network:
11460
11561``` yaml title="app/compose.yaml" hl_lines="5-11 13-15"
11662services :
@@ -130,26 +76,28 @@ networks:
13076 external : true
13177` ` `
13278
133- What's changed?
79+ What's Changed?
80+
81+ 1. Exposed ports were removed.
82+ 1. ` CADDY_SITE_ADDRESS` now listens internally on port `:80`.
83+ 1. The app joins the proxy's network so traffic can be routed to it.
84+ 1. A container alias (`_caddy`) lets the proxy target this service reliably.
13485
135- 1. The exposed ports were removed.
136- 1. Caddy's site address has changed to ` :80` (The application layer no longer
137- handles TLS).
138- 1. We connect to the proxy's network, so the proxy can direct traffic to the
139- app.
140- 1. A container alias was added. This alias allows the proxy to target this
141- container, while still allowing Docker to manage the container name.
86+ You can also remove the `CADDY_SITE_ADDRESS` override in
87+ ` compose.override.yaml` .
14288
143- The `CADDY_SITE_ADDRESS` environment variable can be removed from the override
144- file.
89+ Recreate the app's Caddy container :
14590
14691` ` ` sh
147- docker compose up -d app
92+ docker compose up -d --force-recreate caddy
14893` ` `
14994
150- Commit these changes.
95+ Commit these changes – your app is now "proxy-ready" .
15196
152- # # Deploying
97+ # # 🚀 3. Deploying
98+
99+ The proxy is deployed once (usually manually), and each app is deployed
100+ separately into its own directory.
153101
154102```
155103proxy/
@@ -163,37 +111,75 @@ app/
163111 .env
164112```
165113
166- The proxy is deployed once.
114+ Before deploying, build and push your own proxy image by adding an image name
115+ to the Compose file:
116+
117+ ```yaml title="proxy/compose.yaml" hl_lines="5"
118+ services:
119+ caddy:
120+ build:
121+ context: ./caddy
122+ image: ghcr.io/youruser/yourapp-proxy:0.1.0
123+ ```
124+
125+ Build and push it:
126+
127+ ``` sh
128+ docker compose build
129+ docker compose push
130+ ```
167131
168- On the server, create a proxy directory:
132+ Create a proxy directory on the server :
169133
170134``` sh
171135mkdir proxy
172136```
173137
174- Copy your Compose file to the server :
138+ Copy the proxy's Compose file:
175139
176140``` sh
177141scp proxy/compose.yaml app-backend:proxy/
178142```
179143
180- > You might also point a second hostname to an idle stack for testing.
144+ Start the proxy:
181145
182- ## Deploy the app
146+ docker compose up -d
147+
148+ ## 🆕 4. Deploy the New App Stack
149+
150+ Deploy your app into a new directory (e.g. ` b/ ` ):
151+
152+ ``` sh
153+ scp compose.yaml yourserver:app/b/
154+ ```
155+
156+ Start it on the server:
183157
184158``` sh
159+ cd app/b
185160docker compose up -d
186161```
187162
188- ### Flip traffic
163+ Optionally, verify it's healthy before switching traffic:
164+
165+ ``` sh
166+ docker compose exec -T caddy curl -fsS http://caddy:80/healthz
167+ ```
168+
169+ ## 🔁 5. Flip Traffic
189170
190171``` sh
191172cd proxy
192173docker compose exec caddy curl -X PATCH -d ' "newapp_caddy:80"' \
193174 http://localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/upstreams/0/dial
194175```
195176
196- ## Github Actions Workflow
177+ Traffic now points to the new stack.
178+
179+ ## ⚡ GitHub Actions Example
180+
181+ <details >
182+ <summary >Show full workflow</summary >
197183
198184``` yaml title=".github/workflows/ci.yaml"
199185name : Deploy
@@ -271,3 +257,5 @@ jobs:
271257 mkdir -p /var/log/sku-generator
272258 echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") ${{ github.sha }}" >> /var/log/sku-generator/deploy.log
273259` ` `
260+
261+ </details>
0 commit comments