detached 5dcaefe

docs: Update README to reflect Podman integration and rootless setup

- Replace Docker commands with Podman equivalents for building, running, and pushing images.
- Enhance local-first development section to highlight Podman's rootless container capabilities.
- Update cost comparison and installation instructions to focus on Podman.
- Add detailed steps for configuring Podman as a user service and firewall setup.
- Revise deployment instructions to align with Podman usage.
commit
5dcaefe013d4a5f1bf4238dab005a46110fbc28b
author
bamen · · 2025-06-07 07:37 UTC
parent
a7b3a9b
signature
unsigned
1 file · +100 -43
M README.md +100 -43
@@ -25,12 +25,12 @@ Gordon is the missing piece that makes container deployment on budget VPS server
2525
2626 ```bash
2727 # 1. Build & test on YOUR machine
28-docker build -t myapp .
29-docker run -p 8080:8080 myapp # Works? Great!
28+podman build -t myapp .
29+podman run -p 8080:8080 myapp # Works? Great!
3030
3131 # 2. Push to deploy
32-docker tag myapp registry.yourdomain.com/myapp:latest
33-docker push registry.yourdomain.com/myapp:latest
32+podman tag myapp registry.yourdomain.com/myapp:latest
33+podman push registry.yourdomain.com/myapp:latest
3434
3535 # 3. That's it. Gordon deploys it automatically.
3636 ```
@@ -54,10 +54,10 @@ Save the file. Gordon redeploys the previous version. Problem solved in seconds.
5454 ## ✨ Key Features
5555
5656 ### 🏠 Local-First Development
57-**Your machine is the build server.** Test locally, push when ready. No waiting for remote builds.
57+**Your machine is the build server.** Test locally with Podman's rootless containers, push when ready. No waiting for remote builds.
5858
59-### 🏦 Built-in Docker Registry
60-Your VPS becomes a private Docker registry. No Docker Hub subscription needed.
59+### 🏦 Built-in Container Registry
60+Your VPS becomes a private container registry (Docker/Podman compatible). No Docker Hub subscription needed.
6161
6262 ### 🔄 Push-to-Deploy Magic
6363 Gordon watches for new images and deploys them instantly to configured domains.
@@ -74,22 +74,39 @@ Push new versions anytime. Gordon handles graceful container swaps.
7474 ### 🚀 Automatic Deployment
7575 Containers deploy instantly when you push new images. No manual deployment steps needed.
7676
77-## 💰 Cost Comparison
78-
79-| Solution | Monthly Cost | Setup Complexity | # Apps |
80-|----------|-------------|------------------|--------|
81-| Heroku | $7-25/app | ⭐ | Limited |
82-| AWS ECS | $50-200+ | ⭐⭐⭐⭐⭐ | Unlimited |
83-| Kubernetes | $100+ | ⭐⭐⭐⭐⭐ | Unlimited |
84-| **Gordon + VPS** | **$5-20 total** | **⭐⭐** | **Unlimited** |
85-
8677 ## 🚀 Quick Start (5 minutes)
8778
88-### 1. Get a VPS & Install Docker
79+### 1. Get a VPS & Install Podman (Rootless & Secure)
8980 ```bash
9081 # Any VPS provider: DigitalOcean, Linode, Vultr, Hetzner
9182 # Ubuntu/Debian recommended
92-curl -fsSL https://get.docker.com | sh
83+
84+# Install Podman (more secure than Docker)
85+sudo apt update
86+sudo apt install -y podman
87+
88+# Enable rootless mode for enhanced security
89+echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.conf
90+sudo sysctl -p
91+
92+# Configure user for rootless containers
93+sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
94+
95+# Start user services (no root required!)
96+systemctl --user enable --now podman.socket
97+
98+# Configure registries for your Gordon registry
99+mkdir -p ~/.config/containers
100+tee ~/.config/containers/registries.conf > /dev/null <<EOF
101+[registries.search]
102+registries = ['docker.io', 'registry.yourdomain.com']
103+
104+[registries.insecure]
105+registries = ['registry.yourdomain.com']
106+
107+[registries.block]
108+registries = []
109+EOF
93110 ```
94111
95112 ### 2. Install Gordon
@@ -105,7 +122,7 @@ sudo mv gordon-linux-amd64 /usr/local/bin/gordon
105122 [server]
106123 port = 8080
107124 registry_domain = "registry.yourdomain.com"
108-runtime = "auto" # auto-detects Docker/Podman
125+runtime = "podman-rootless" # Secure rootless mode
109126 ssl_email = "you@yourdomain.com"
110127
111128 [registry_auth]
@@ -125,25 +142,64 @@ A *.yourdomain.com → YOUR_VPS_IP
125142 A yourdomain.com → YOUR_VPS_IP
126143 ```
127144
128-### 5. Start Gordon & Configure Firewall
145+### 5. Create Systemd Service (Rootless)
129146 ```bash
130-# Start Gordon
131-sudo gordon start
147+# Create user systemd service (no root privileges needed!)
148+mkdir -p ~/.config/systemd/user
132149
150+tee ~/.config/systemd/user/gordon.service > /dev/null <<EOF
151+[Unit]
152+Description=Gordon Container Platform (Rootless)
153+After=podman.socket
154+Requires=podman.socket
155+
156+[Service]
157+Type=simple
158+Restart=always
159+RestartSec=5
160+Environment=CONTAINER_HOST=unix://%t/podman/podman.sock
161+ExecStart=/usr/local/bin/gordon start
162+WorkingDirectory=%h
163+
164+[Install]
165+WantedBy=default.target
166+EOF
167+
168+# Enable and start the user service
169+systemctl --user daemon-reload
170+systemctl --user enable --now gordon
171+
172+# Enable lingering to start service on boot
173+sudo loginctl enable-linger $USER
174+
175+# Check service status
176+systemctl --user status gordon
177+```
178+
179+### 6. Configure Firewall
180+```bash
133181 # Set up port forwarding (choose one option)
134182
135183 # Option A: iptables (most common)
136184 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
137185 sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8080
138186
187+# Make iptables rules persistent
188+sudo apt-get install iptables-persistent
189+sudo netfilter-persistent save
190+
139191 # Option B: UFW with NAT (Ubuntu)
140192 sudo ufw allow 22,80,443,8080/tcp
141193 echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
142194 sudo sysctl -p
143195
144-# Deploy your first app
145-docker tag myapp:latest registry.yourdomain.com/myapp:latest
146-docker push registry.yourdomain.com/myapp:latest
196+# Authenticate with your Gordon registry
197+podman login registry.yourdomain.com
198+# Use the username/password from your gordon.toml config
199+
200+# Deploy your first app (using podman)
201+podman tag myapp:latest registry.yourdomain.com/myapp:latest
202+podman push registry.yourdomain.com/myapp:latest
147203 # Visit https://app.yourdomain.com 🎉
148204 ```
149205
@@ -152,32 +208,33 @@ docker push registry.yourdomain.com/myapp:latest
152208 ### Deploy a Node.js App
153209 ```bash
154210 # Build and test locally first
155-docker build -t myapp .
156-docker run -p 3000:3000 myapp # Test it!
211+podman build -t myapp .
212+podman run -p 3000:3000 myapp # Test it!
157213
158-# Tag with version AND latest
159-docker tag myapp registry.yourdomain.com/myapp:v1.0.0
160-docker tag myapp registry.yourdomain.com/myapp:latest
214+# Tag with registry prefix for both version and latest
215+podman tag myapp registry.yourdomain.com/myapp:v1.0.0
216+podman tag myapp registry.yourdomain.com/myapp:latest
161217
162-# Push both tags
163-docker push registry.yourdomain.com/myapp:v1.0.0
164-docker push registry.yourdomain.com/myapp:latest
218+# Push both tags to your Gordon registry
219+podman push registry.yourdomain.com/myapp:v1.0.0
220+podman push registry.yourdomain.com/myapp:latest
165221
166-# Auto-deployed to app.yourdomain.com
222+# Gordon automatically detects the push and deploys to app.yourdomain.com
167223 ```
168224
169225 ### Smart Versioning Strategy
170226 ```bash
171-# Always push versioned tags
172-docker tag myapp registry.yourdomain.com/myapp:v1.0.1
173-docker push registry.yourdomain.com/myapp:v1.0.1
227+# Always push versioned tags first
228+podman tag myapp registry.yourdomain.com/myapp:v1.0.1
229+podman push registry.yourdomain.com/myapp:v1.0.1
174230
175-# Update config to test
231+# Update config to test the new version
232+# Edit gordon.toml:
176233 "app.yourdomain.com" = "myapp:v1.0.1"
177234
178-# Happy? Update latest
179-docker tag myapp registry.yourdomain.com/myapp:latest
180-docker push registry.yourdomain.com/myapp:latest
235+# Happy with the new version? Tag and push as latest
236+podman tag registry.yourdomain.com/myapp:v1.0.1 registry.yourdomain.com/myapp:latest
237+podman push registry.yourdomain.com/myapp:latest
181238 ```
182239
183240 ### Instant Rollback When Things Break
@@ -281,8 +338,8 @@ A: Use environment variables in your container or Docker secrets. Gordon doesn't
281338 # Traditional CI/CD
282339 push code → wait for build → hope it works → debug remotely → repeat
283340
284-# The Gordon Way
285-build locally → test locally → push image → instant deploy
341+# The Gordon Way (with Podman)
342+podman build locally → test locally → push image → instant deploy
286343 ```
287344
288345 ## 🏗️ Architecture
@@ -25,12 +25,12 @@ Gordon is the missing piece that makes container deployment on budget VPS server
25 25
26 ```bash26 ```bash
27 # 1. Build & test on YOUR machine27 # 1. Build & test on YOUR machine
28-docker build -t myapp .28+podman build -t myapp .
29-docker run -p 8080:8080 myapp # Works? Great!29+podman run -p 8080:8080 myapp # Works? Great!
30 30
31 # 2. Push to deploy31 # 2. Push to deploy
32-docker tag myapp registry.yourdomain.com/myapp:latest32+podman tag myapp registry.yourdomain.com/myapp:latest
33-docker push registry.yourdomain.com/myapp:latest33+podman push registry.yourdomain.com/myapp:latest
34 34
35 # 3. That's it. Gordon deploys it automatically.35 # 3. That's it. Gordon deploys it automatically.
36 ```36 ```
@@ -54,10 +54,10 @@ Save the file. Gordon redeploys the previous version. Problem solved in seconds.
54 ## ✨ Key Features54 ## ✨ Key Features
55 55
56 ### 🏠 Local-First Development56 ### 🏠 Local-First Development
57-**Your machine is the build server.** Test locally, push when ready. No waiting for remote builds.57+**Your machine is the build server.** Test locally with Podman's rootless containers, push when ready. No waiting for remote builds.
58 58
59-### 🏦 Built-in Docker Registry59+### 🏦 Built-in Container Registry
60-Your VPS becomes a private Docker registry. No Docker Hub subscription needed.60+Your VPS becomes a private container registry (Docker/Podman compatible). No Docker Hub subscription needed.
61 61
62 ### 🔄 Push-to-Deploy Magic62 ### 🔄 Push-to-Deploy Magic
63 Gordon watches for new images and deploys them instantly to configured domains.63 Gordon watches for new images and deploys them instantly to configured domains.
@@ -74,22 +74,39 @@ Push new versions anytime. Gordon handles graceful container swaps.
74 ### 🚀 Automatic Deployment74 ### 🚀 Automatic Deployment
75 Containers deploy instantly when you push new images. No manual deployment steps needed.75 Containers deploy instantly when you push new images. No manual deployment steps needed.
76 76
77-## 💰 Cost Comparison
78-
79-| Solution | Monthly Cost | Setup Complexity | # Apps |
80-|----------|-------------|------------------|--------|
81-| Heroku | $7-25/app | ⭐ | Limited |
82-| AWS ECS | $50-200+ | ⭐⭐⭐⭐⭐ | Unlimited |
83-| Kubernetes | $100+ | ⭐⭐⭐⭐⭐ | Unlimited |
84-| **Gordon + VPS** | **$5-20 total** | **⭐⭐** | **Unlimited** |
85-
86 ## 🚀 Quick Start (5 minutes)77 ## 🚀 Quick Start (5 minutes)
87 78
88-### 1. Get a VPS & Install Docker79+### 1. Get a VPS & Install Podman (Rootless & Secure)
89 ```bash80 ```bash
90 # Any VPS provider: DigitalOcean, Linode, Vultr, Hetzner81 # Any VPS provider: DigitalOcean, Linode, Vultr, Hetzner
91 # Ubuntu/Debian recommended82 # Ubuntu/Debian recommended
92-curl -fsSL https://get.docker.com | sh83+
84+# Install Podman (more secure than Docker)
85+sudo apt update
86+sudo apt install -y podman
87+
88+# Enable rootless mode for enhanced security
89+echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.conf
90+sudo sysctl -p
91+
92+# Configure user for rootless containers
93+sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
94+
95+# Start user services (no root required!)
96+systemctl --user enable --now podman.socket
97+
98+# Configure registries for your Gordon registry
99+mkdir -p ~/.config/containers
100+tee ~/.config/containers/registries.conf > /dev/null <<EOF
101+[registries.search]
102+registries = ['docker.io', 'registry.yourdomain.com']
103+
104+[registries.insecure]
105+registries = ['registry.yourdomain.com']
106+
107+[registries.block]
108+registries = []
109+EOF
93 ```110 ```
94 111
95 ### 2. Install Gordon112 ### 2. Install Gordon
@@ -105,7 +122,7 @@ sudo mv gordon-linux-amd64 /usr/local/bin/gordon
105 [server]122 [server]
106 port = 8080123 port = 8080
107 registry_domain = "registry.yourdomain.com"124 registry_domain = "registry.yourdomain.com"
108-runtime = "auto" # auto-detects Docker/Podman125+runtime = "podman-rootless" # Secure rootless mode
109 ssl_email = "you@yourdomain.com"126 ssl_email = "you@yourdomain.com"
110 127
111 [registry_auth]128 [registry_auth]
@@ -125,25 +142,64 @@ A *.yourdomain.com → YOUR_VPS_IP
125 A yourdomain.com → YOUR_VPS_IP142 A yourdomain.com → YOUR_VPS_IP
126 ```143 ```
127 144
128-### 5. Start Gordon & Configure Firewall145+### 5. Create Systemd Service (Rootless)
129 ```bash146 ```bash
130-# Start Gordon147+# Create user systemd service (no root privileges needed!)
131-sudo gordon start148+mkdir -p ~/.config/systemd/user
132 149
150+tee ~/.config/systemd/user/gordon.service > /dev/null <<EOF
151+[Unit]
152+Description=Gordon Container Platform (Rootless)
153+After=podman.socket
154+Requires=podman.socket
155+
156+[Service]
157+Type=simple
158+Restart=always
159+RestartSec=5
160+Environment=CONTAINER_HOST=unix://%t/podman/podman.sock
161+ExecStart=/usr/local/bin/gordon start
162+WorkingDirectory=%h
163+
164+[Install]
165+WantedBy=default.target
166+EOF
167+
168+# Enable and start the user service
169+systemctl --user daemon-reload
170+systemctl --user enable --now gordon
171+
172+# Enable lingering to start service on boot
173+sudo loginctl enable-linger $USER
174+
175+# Check service status
176+systemctl --user status gordon
177+```
178+
179+### 6. Configure Firewall
180+```bash
133 # Set up port forwarding (choose one option)181 # Set up port forwarding (choose one option)
134 182
135 # Option A: iptables (most common)183 # Option A: iptables (most common)
136 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080184 sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
137 sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8080185 sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8080
138 186
187+# Make iptables rules persistent
188+sudo apt-get install iptables-persistent
189+sudo netfilter-persistent save
190+
139 # Option B: UFW with NAT (Ubuntu)191 # Option B: UFW with NAT (Ubuntu)
140 sudo ufw allow 22,80,443,8080/tcp192 sudo ufw allow 22,80,443,8080/tcp
141 echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf193 echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
142 sudo sysctl -p194 sudo sysctl -p
143 195
144-# Deploy your first app196+# Authenticate with your Gordon registry
145-docker tag myapp:latest registry.yourdomain.com/myapp:latest197+podman login registry.yourdomain.com
146-docker push registry.yourdomain.com/myapp:latest198+# Use the username/password from your gordon.toml config
199+
200+# Deploy your first app (using podman)
201+podman tag myapp:latest registry.yourdomain.com/myapp:latest
202+podman push registry.yourdomain.com/myapp:latest
147 # Visit https://app.yourdomain.com 🎉203 # Visit https://app.yourdomain.com 🎉
148 ```204 ```
149 205
@@ -152,32 +208,33 @@ docker push registry.yourdomain.com/myapp:latest
152 ### Deploy a Node.js App208 ### Deploy a Node.js App
153 ```bash209 ```bash
154 # Build and test locally first210 # Build and test locally first
155-docker build -t myapp .211+podman build -t myapp .
156-docker run -p 3000:3000 myapp # Test it!212+podman run -p 3000:3000 myapp # Test it!
157 213
158-# Tag with version AND latest214+# Tag with registry prefix for both version and latest
159-docker tag myapp registry.yourdomain.com/myapp:v1.0.0215+podman tag myapp registry.yourdomain.com/myapp:v1.0.0
160-docker tag myapp registry.yourdomain.com/myapp:latest216+podman tag myapp registry.yourdomain.com/myapp:latest
161 217
162-# Push both tags218+# Push both tags to your Gordon registry
163-docker push registry.yourdomain.com/myapp:v1.0.0219+podman push registry.yourdomain.com/myapp:v1.0.0
164-docker push registry.yourdomain.com/myapp:latest220+podman push registry.yourdomain.com/myapp:latest
165 221
166-# Auto-deployed to app.yourdomain.com222+# Gordon automatically detects the push and deploys to app.yourdomain.com
167 ```223 ```
168 224
169 ### Smart Versioning Strategy225 ### Smart Versioning Strategy
170 ```bash226 ```bash
171-# Always push versioned tags227+# Always push versioned tags first
172-docker tag myapp registry.yourdomain.com/myapp:v1.0.1228+podman tag myapp registry.yourdomain.com/myapp:v1.0.1
173-docker push registry.yourdomain.com/myapp:v1.0.1229+podman push registry.yourdomain.com/myapp:v1.0.1
174 230
175-# Update config to test231+# Update config to test the new version
232+# Edit gordon.toml:
176 "app.yourdomain.com" = "myapp:v1.0.1"233 "app.yourdomain.com" = "myapp:v1.0.1"
177 234
178-# Happy? Update latest235+# Happy with the new version? Tag and push as latest
179-docker tag myapp registry.yourdomain.com/myapp:latest236+podman tag registry.yourdomain.com/myapp:v1.0.1 registry.yourdomain.com/myapp:latest
180-docker push registry.yourdomain.com/myapp:latest237+podman push registry.yourdomain.com/myapp:latest
181 ```238 ```
182 239
183 ### Instant Rollback When Things Break240 ### Instant Rollback When Things Break
@@ -281,8 +338,8 @@ A: Use environment variables in your container or Docker secrets. Gordon doesn't
281 # Traditional CI/CD338 # Traditional CI/CD
282 push code → wait for build → hope it works → debug remotely → repeat339 push code → wait for build → hope it works → debug remotely → repeat
283 340
284-# The Gordon Way341+# The Gordon Way (with Podman)
285-build locally → test locally → push image → instant deploy342+podman build locally → test locally → push image → instant deploy
286 ```343 ```
287 344
288 ## 🏗️ Architecture345 ## 🏗️ Architecture

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close