claude-agent-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/bin/claude-framework +3 -0
- package/framework/agents/design-lead.md +240 -0
- package/framework/agents/product-owner.md +179 -0
- package/framework/agents/tech-lead.md +226 -0
- package/framework/commands/ayuda.md +127 -0
- package/framework/commands/a/303/261adir.md +98 -0
- package/framework/commands/backup.md +397 -0
- package/framework/commands/cambiar.md +110 -0
- package/framework/commands/cloud.md +457 -0
- package/framework/commands/code.md +142 -0
- package/framework/commands/debug.md +334 -0
- package/framework/commands/deploy.md +383 -0
- package/framework/commands/deshacer.md +120 -0
- package/framework/commands/estado.md +218 -0
- package/framework/commands/explica.md +227 -0
- package/framework/commands/feature.md +120 -0
- package/framework/commands/git.md +427 -0
- package/framework/commands/historial.md +202 -0
- package/framework/commands/learn.md +408 -0
- package/framework/commands/movil.md +245 -0
- package/framework/commands/nuevo.md +118 -0
- package/framework/commands/plan.md +134 -0
- package/framework/commands/prd.md +113 -0
- package/framework/commands/probar.md +148 -0
- package/framework/commands/revisar.md +208 -0
- package/framework/commands/seeds.md +230 -0
- package/framework/commands/seguridad.md +226 -0
- package/framework/commands/tasks.md +157 -0
- package/framework/skills/architecture/algorithms.md +970 -0
- package/framework/skills/architecture/clean-code.md +1080 -0
- package/framework/skills/architecture/design-patterns.md +1984 -0
- package/framework/skills/architecture/functional-programming.md +972 -0
- package/framework/skills/architecture/solid.md +991 -0
- package/framework/skills/cloud/cloud-aws.md +848 -0
- package/framework/skills/cloud/cloud-azure.md +931 -0
- package/framework/skills/cloud/cloud-gcp.md +848 -0
- package/framework/skills/cloud/message-queues.md +1229 -0
- package/framework/skills/core/accessibility.md +401 -0
- package/framework/skills/core/api.md +474 -0
- package/framework/skills/core/authentication.md +306 -0
- package/framework/skills/core/authorization.md +388 -0
- package/framework/skills/core/background-jobs.md +341 -0
- package/framework/skills/core/caching.md +473 -0
- package/framework/skills/core/code-review.md +341 -0
- package/framework/skills/core/controllers.md +290 -0
- package/framework/skills/core/cua.md +285 -0
- package/framework/skills/core/documentation.md +472 -0
- package/framework/skills/core/file-uploads.md +351 -0
- package/framework/skills/core/hotwire-native.md +296 -0
- package/framework/skills/core/hotwire.md +278 -0
- package/framework/skills/core/i18n.md +334 -0
- package/framework/skills/core/imports-exports.md +750 -0
- package/framework/skills/core/infrastructure.md +337 -0
- package/framework/skills/core/models.md +228 -0
- package/framework/skills/core/notifications.md +672 -0
- package/framework/skills/core/payments.md +581 -0
- package/framework/skills/core/performance.md +361 -0
- package/framework/skills/core/rails-scaffold.md +131 -0
- package/framework/skills/core/search.md +518 -0
- package/framework/skills/core/security.md +565 -0
- package/framework/skills/core/seeds.md +307 -0
- package/framework/skills/core/seo.md +542 -0
- package/framework/skills/core/testing.md +393 -0
- package/framework/skills/core/views.md +260 -0
- package/framework/skills/core/websockets.md +564 -0
- package/framework/skills/data/advanced-sql.md +1204 -0
- package/framework/skills/data/nosql.md +1141 -0
- package/framework/skills/devops/containers-advanced.md +1237 -0
- package/framework/skills/devops/debugging.md +834 -0
- package/framework/skills/devops/git-workflow.md +752 -0
- package/framework/skills/devops/networking.md +932 -0
- package/framework/skills/devops/shell-scripting.md +1132 -0
- package/framework/sub-agents/architecture-patterns-agent.md +1450 -0
- package/framework/sub-agents/cloud-agent.md +677 -0
- package/framework/sub-agents/data.md +504 -0
- package/framework/sub-agents/debugging-agent.md +554 -0
- package/framework/sub-agents/devops.md +483 -0
- package/framework/sub-agents/docs.md +176 -0
- package/framework/sub-agents/frontend-dev.md +349 -0
- package/framework/sub-agents/git-workflow-agent.md +697 -0
- package/framework/sub-agents/integrations.md +630 -0
- package/framework/sub-agents/native-dev.md +434 -0
- package/framework/sub-agents/qa.md +138 -0
- package/framework/sub-agents/rails-dev.md +375 -0
- package/framework/sub-agents/security.md +526 -0
- package/framework/sub-agents/ui.md +437 -0
- package/framework/sub-agents/ux.md +284 -0
- package/framework/templates/api-spec.md +500 -0
- package/framework/templates/component-spec.md +248 -0
- package/framework/templates/feature.json +13 -0
- package/framework/templates/model-spec.md +318 -0
- package/framework/templates/prd-template.md +80 -0
- package/framework/templates/task-plan.md +122 -0
- package/framework/templates/task-user-story.md +52 -0
- package/framework/templates/technical-spec.md +260 -0
- package/framework/templates/user-story.md +95 -0
- package/package.json +42 -0
- package/project-templates/CLAUDE.md +42 -0
- package/project-templates/contexts/architecture.md +25 -0
- package/project-templates/contexts/conventions.md +46 -0
- package/project-templates/contexts/design-system.md +47 -0
- package/project-templates/contexts/requirements.md +38 -0
- package/project-templates/contexts/stack.md +30 -0
- package/project-templates/history/active/models.md +11 -0
- package/project-templates/history/changelog.md +15 -0
- package/project-templates/workspace/.gitkeep +0 -0
- package/src/cli.js +52 -0
- package/src/init.js +104 -0
- package/src/status.js +75 -0
- package/src/update.js +88 -0
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
# Skill: Networking
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Fundamentos de redes que todo desarrollador web necesita conocer para debuggear, configurar y desplegar aplicaciones Rails.
|
|
6
|
+
|
|
7
|
+
## DNS (Domain Name System)
|
|
8
|
+
|
|
9
|
+
### Tipos de registros
|
|
10
|
+
|
|
11
|
+
| Tipo | Uso | Ejemplo |
|
|
12
|
+
|------|-----|---------|
|
|
13
|
+
| A | IPv4 address | `example.com -> 93.184.216.34` |
|
|
14
|
+
| AAAA | IPv6 address | `example.com -> 2606:2800:220:1:...` |
|
|
15
|
+
| CNAME | Alias a otro dominio | `www.example.com -> example.com` |
|
|
16
|
+
| MX | Mail server | `example.com -> mail.example.com (priority 10)` |
|
|
17
|
+
| TXT | Texto arbitrario | SPF, DKIM, verificación |
|
|
18
|
+
| NS | Nameservers | `example.com -> ns1.provider.com` |
|
|
19
|
+
| SRV | Service locator | `_sip._tcp.example.com` |
|
|
20
|
+
| CAA | Certificate Authority | Qué CAs pueden emitir certificados |
|
|
21
|
+
|
|
22
|
+
### TTL (Time To Live)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Ver TTL de un registro
|
|
26
|
+
dig example.com +noall +answer
|
|
27
|
+
|
|
28
|
+
# Resultado:
|
|
29
|
+
# example.com. 300 IN A 93.184.216.34
|
|
30
|
+
# ^^^
|
|
31
|
+
# TTL en segundos
|
|
32
|
+
|
|
33
|
+
# TTLs recomendados:
|
|
34
|
+
# - Producción estable: 3600 (1 hora) o más
|
|
35
|
+
# - Antes de migración: 300 (5 minutos)
|
|
36
|
+
# - Durante migración: 60 (1 minuto)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Configuración DNS para Rails
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
# Registros típicos para una app Rails
|
|
43
|
+
|
|
44
|
+
# Dominio principal
|
|
45
|
+
example.com. A IP_DEL_SERVIDOR
|
|
46
|
+
example.com. AAAA IPv6_DEL_SERVIDOR
|
|
47
|
+
|
|
48
|
+
# Subdominio www
|
|
49
|
+
www.example.com. CNAME example.com.
|
|
50
|
+
|
|
51
|
+
# API subdomain
|
|
52
|
+
api.example.com. A IP_DEL_API_SERVER
|
|
53
|
+
|
|
54
|
+
# Email (si usas servicio externo)
|
|
55
|
+
example.com. MX 10 mx1.mailprovider.com.
|
|
56
|
+
example.com. MX 20 mx2.mailprovider.com.
|
|
57
|
+
|
|
58
|
+
# SPF para email
|
|
59
|
+
example.com. TXT "v=spf1 include:_spf.mailprovider.com ~all"
|
|
60
|
+
|
|
61
|
+
# Verificación de dominio
|
|
62
|
+
example.com. TXT "google-site-verification=xxx"
|
|
63
|
+
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Debugging DNS
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Lookup básico
|
|
70
|
+
nslookup example.com
|
|
71
|
+
dig example.com
|
|
72
|
+
|
|
73
|
+
# Ver todos los registros
|
|
74
|
+
dig example.com ANY
|
|
75
|
+
|
|
76
|
+
# Query a servidor específico
|
|
77
|
+
dig @8.8.8.8 example.com
|
|
78
|
+
|
|
79
|
+
# Ver cadena completa de resolución
|
|
80
|
+
dig +trace example.com
|
|
81
|
+
|
|
82
|
+
# Reverse lookup
|
|
83
|
+
dig -x 93.184.216.34
|
|
84
|
+
|
|
85
|
+
# Ver registros MX
|
|
86
|
+
dig example.com MX
|
|
87
|
+
|
|
88
|
+
# Ver registros TXT
|
|
89
|
+
dig example.com TXT
|
|
90
|
+
|
|
91
|
+
# Verificar propagación
|
|
92
|
+
dig example.com @ns1.google.com
|
|
93
|
+
dig example.com @ns1.cloudflare.com
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## TCP/IP
|
|
97
|
+
|
|
98
|
+
### Puertos comunes
|
|
99
|
+
|
|
100
|
+
| Puerto | Servicio |
|
|
101
|
+
|--------|----------|
|
|
102
|
+
| 22 | SSH |
|
|
103
|
+
| 80 | HTTP |
|
|
104
|
+
| 443 | HTTPS |
|
|
105
|
+
| 3000 | Rails (development) |
|
|
106
|
+
| 5432 | PostgreSQL |
|
|
107
|
+
| 6379 | Redis |
|
|
108
|
+
| 11211 | Memcached |
|
|
109
|
+
| 3306 | MySQL |
|
|
110
|
+
| 27017 | MongoDB |
|
|
111
|
+
|
|
112
|
+
### Sockets
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
# En Rails, Puma escucha en socket
|
|
116
|
+
# config/puma.rb
|
|
117
|
+
|
|
118
|
+
# Socket TCP (para desarrollo)
|
|
119
|
+
port ENV.fetch("PORT") { 3000 }
|
|
120
|
+
|
|
121
|
+
# Unix socket (para producción con Nginx)
|
|
122
|
+
bind "unix:///var/run/puma.sock"
|
|
123
|
+
|
|
124
|
+
# O ambos
|
|
125
|
+
if ENV["RAILS_ENV"] == "production"
|
|
126
|
+
bind "unix:///var/run/puma.sock"
|
|
127
|
+
else
|
|
128
|
+
port 3000
|
|
129
|
+
end
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### TCP Handshake
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Cliente Servidor
|
|
136
|
+
| |
|
|
137
|
+
| -------- SYN --------> | 1. Cliente inicia
|
|
138
|
+
| <----- SYN-ACK ------ | 2. Servidor responde
|
|
139
|
+
| -------- ACK --------> | 3. Conexión establecida
|
|
140
|
+
| |
|
|
141
|
+
| <==== Datos ===> | 4. Intercambio de datos
|
|
142
|
+
| |
|
|
143
|
+
| -------- FIN --------> | 5. Cliente cierra
|
|
144
|
+
| <----- ACK ------- | 6. Servidor confirma
|
|
145
|
+
| <----- FIN ------- | 7. Servidor cierra
|
|
146
|
+
| -------- ACK --------> | 8. Cliente confirma
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Verificar conexiones
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Ver conexiones activas
|
|
153
|
+
netstat -an | grep LISTEN
|
|
154
|
+
ss -tlnp
|
|
155
|
+
|
|
156
|
+
# Ver conexiones a puerto específico
|
|
157
|
+
netstat -an | grep :3000
|
|
158
|
+
lsof -i :3000
|
|
159
|
+
|
|
160
|
+
# Ver estado de conexiones
|
|
161
|
+
netstat -s
|
|
162
|
+
|
|
163
|
+
# Verificar si puerto está abierto
|
|
164
|
+
nc -zv localhost 3000
|
|
165
|
+
telnet localhost 3000
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## HTTP/HTTPS
|
|
169
|
+
|
|
170
|
+
### Métodos HTTP
|
|
171
|
+
|
|
172
|
+
| Método | Uso | Idempotente | Body |
|
|
173
|
+
|--------|-----|-------------|------|
|
|
174
|
+
| GET | Obtener recurso | Sí | No |
|
|
175
|
+
| POST | Crear recurso | No | Sí |
|
|
176
|
+
| PUT | Reemplazar recurso | Sí | Sí |
|
|
177
|
+
| PATCH | Actualizar parcial | No | Sí |
|
|
178
|
+
| DELETE | Eliminar recurso | Sí | No |
|
|
179
|
+
| HEAD | Solo headers | Sí | No |
|
|
180
|
+
| OPTIONS | Ver opciones | Sí | No |
|
|
181
|
+
|
|
182
|
+
### Headers comunes
|
|
183
|
+
|
|
184
|
+
```http
|
|
185
|
+
# Request headers
|
|
186
|
+
GET /users HTTP/1.1
|
|
187
|
+
Host: api.example.com
|
|
188
|
+
Accept: application/json
|
|
189
|
+
Content-Type: application/json
|
|
190
|
+
Authorization: Bearer eyJhbG...
|
|
191
|
+
User-Agent: MyApp/1.0
|
|
192
|
+
Accept-Language: es-ES,es;q=0.9
|
|
193
|
+
Cache-Control: no-cache
|
|
194
|
+
X-Request-ID: abc123
|
|
195
|
+
|
|
196
|
+
# Response headers
|
|
197
|
+
HTTP/1.1 200 OK
|
|
198
|
+
Content-Type: application/json; charset=utf-8
|
|
199
|
+
Content-Length: 1234
|
|
200
|
+
Cache-Control: max-age=3600
|
|
201
|
+
ETag: "abc123"
|
|
202
|
+
X-Request-Id: abc123
|
|
203
|
+
X-Runtime: 0.045
|
|
204
|
+
Set-Cookie: _session_id=xxx; path=/; HttpOnly; Secure; SameSite=Lax
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Status codes
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
# 2xx - Éxito
|
|
211
|
+
200 OK - Éxito general
|
|
212
|
+
201 Created - Recurso creado
|
|
213
|
+
204 No Content - Éxito sin body
|
|
214
|
+
|
|
215
|
+
# 3xx - Redirección
|
|
216
|
+
301 Moved Permanently - Redirección permanente
|
|
217
|
+
302 Found - Redirección temporal
|
|
218
|
+
304 Not Modified - Usar cache
|
|
219
|
+
|
|
220
|
+
# 4xx - Error del cliente
|
|
221
|
+
400 Bad Request - Request malformado
|
|
222
|
+
401 Unauthorized - No autenticado
|
|
223
|
+
403 Forbidden - No autorizado
|
|
224
|
+
404 Not Found - Recurso no existe
|
|
225
|
+
422 Unprocessable Entity - Validación fallida
|
|
226
|
+
429 Too Many Requests - Rate limit
|
|
227
|
+
|
|
228
|
+
# 5xx - Error del servidor
|
|
229
|
+
500 Internal Server Error - Error del servidor
|
|
230
|
+
502 Bad Gateway - Proxy/gateway error
|
|
231
|
+
503 Service Unavailable - Servidor sobrecargado
|
|
232
|
+
504 Gateway Timeout - Timeout del proxy
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Cookies
|
|
236
|
+
|
|
237
|
+
```ruby
|
|
238
|
+
# En Rails controller
|
|
239
|
+
class SessionsController < ApplicationController
|
|
240
|
+
def create
|
|
241
|
+
# Setear cookie
|
|
242
|
+
cookies[:user_id] = {
|
|
243
|
+
value: user.id,
|
|
244
|
+
expires: 1.week.from_now,
|
|
245
|
+
httponly: true, # No accesible desde JS
|
|
246
|
+
secure: Rails.env.production?, # Solo HTTPS
|
|
247
|
+
same_site: :lax # Protección CSRF
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
# Cookie encriptada
|
|
251
|
+
cookies.encrypted[:user_id] = user.id
|
|
252
|
+
|
|
253
|
+
# Cookie firmada (no encriptada pero verificable)
|
|
254
|
+
cookies.signed[:user_id] = user.id
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def destroy
|
|
258
|
+
cookies.delete(:user_id)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Session cookie (automática)
|
|
263
|
+
# config/initializers/session_store.rb
|
|
264
|
+
Rails.application.config.session_store :cookie_store,
|
|
265
|
+
key: "_myapp_session",
|
|
266
|
+
secure: Rails.env.production?,
|
|
267
|
+
same_site: :lax,
|
|
268
|
+
expire_after: 24.hours
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## SSL/TLS
|
|
272
|
+
|
|
273
|
+
### Certificados
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Generar certificado autofirmado (desarrollo)
|
|
277
|
+
openssl req -x509 -nodes -days 365 \
|
|
278
|
+
-newkey rsa:2048 \
|
|
279
|
+
-keyout localhost.key \
|
|
280
|
+
-out localhost.crt \
|
|
281
|
+
-subj "/CN=localhost"
|
|
282
|
+
|
|
283
|
+
# Ver información de certificado
|
|
284
|
+
openssl x509 -in certificate.crt -text -noout
|
|
285
|
+
|
|
286
|
+
# Verificar certificado de sitio
|
|
287
|
+
openssl s_client -connect example.com:443 -servername example.com
|
|
288
|
+
|
|
289
|
+
# Ver fecha de expiración
|
|
290
|
+
echo | openssl s_client -servername example.com \
|
|
291
|
+
-connect example.com:443 2>/dev/null | \
|
|
292
|
+
openssl x509 -noout -dates
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Let's Encrypt con Certbot
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Instalar certbot
|
|
299
|
+
sudo apt install certbot python3-certbot-nginx
|
|
300
|
+
|
|
301
|
+
# Obtener certificado
|
|
302
|
+
sudo certbot --nginx -d example.com -d www.example.com
|
|
303
|
+
|
|
304
|
+
# Solo obtener certificado (sin configurar nginx)
|
|
305
|
+
sudo certbot certonly --standalone -d example.com
|
|
306
|
+
|
|
307
|
+
# Renovar certificados
|
|
308
|
+
sudo certbot renew
|
|
309
|
+
|
|
310
|
+
# Renovación automática (cron)
|
|
311
|
+
0 0 1 * * certbot renew --quiet
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### SSL Termination
|
|
315
|
+
|
|
316
|
+
```nginx
|
|
317
|
+
# nginx.conf - SSL termination en Nginx
|
|
318
|
+
|
|
319
|
+
upstream rails_app {
|
|
320
|
+
server unix:///var/run/puma.sock fail_timeout=0;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
server {
|
|
324
|
+
listen 80;
|
|
325
|
+
server_name example.com;
|
|
326
|
+
return 301 https://$server_name$request_uri;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
server {
|
|
330
|
+
listen 443 ssl http2;
|
|
331
|
+
server_name example.com;
|
|
332
|
+
|
|
333
|
+
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
|
|
334
|
+
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
|
|
335
|
+
|
|
336
|
+
# SSL configuration
|
|
337
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
338
|
+
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
|
|
339
|
+
ssl_prefer_server_ciphers off;
|
|
340
|
+
|
|
341
|
+
# HSTS
|
|
342
|
+
add_header Strict-Transport-Security "max-age=63072000" always;
|
|
343
|
+
|
|
344
|
+
location / {
|
|
345
|
+
proxy_pass http://rails_app;
|
|
346
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
347
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
348
|
+
proxy_set_header Host $http_host;
|
|
349
|
+
proxy_redirect off;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Proxies
|
|
355
|
+
|
|
356
|
+
### Forward Proxy
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
Cliente -> Forward Proxy -> Internet -> Servidor
|
|
360
|
+
|
|
361
|
+
# Uso: anonimato, filtrado, cache
|
|
362
|
+
# El cliente sabe que usa proxy
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Reverse Proxy (Nginx)
|
|
366
|
+
|
|
367
|
+
```
|
|
368
|
+
Internet -> Nginx (reverse proxy) -> Rails App
|
|
369
|
+
|
|
370
|
+
# Uso: SSL termination, load balancing, cache
|
|
371
|
+
# El cliente no sabe que hay proxy
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Configuración Nginx para Rails
|
|
375
|
+
|
|
376
|
+
```nginx
|
|
377
|
+
# /etc/nginx/sites-available/myapp
|
|
378
|
+
|
|
379
|
+
upstream puma {
|
|
380
|
+
server unix:///var/www/myapp/shared/sockets/puma.sock;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
server {
|
|
384
|
+
listen 80;
|
|
385
|
+
server_name example.com;
|
|
386
|
+
|
|
387
|
+
root /var/www/myapp/current/public;
|
|
388
|
+
|
|
389
|
+
# Servir archivos estáticos directamente
|
|
390
|
+
location ^~ /assets/ {
|
|
391
|
+
gzip_static on;
|
|
392
|
+
expires max;
|
|
393
|
+
add_header Cache-Control public;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
# Uploads
|
|
397
|
+
location ^~ /uploads/ {
|
|
398
|
+
expires max;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
# Rails app
|
|
402
|
+
location / {
|
|
403
|
+
try_files $uri @puma;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
location @puma {
|
|
407
|
+
proxy_pass http://puma;
|
|
408
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
409
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
410
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
411
|
+
proxy_set_header Host $http_host;
|
|
412
|
+
proxy_redirect off;
|
|
413
|
+
|
|
414
|
+
# WebSocket support
|
|
415
|
+
proxy_http_version 1.1;
|
|
416
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
417
|
+
proxy_set_header Connection "upgrade";
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
# Error pages
|
|
421
|
+
error_page 500 502 503 504 /500.html;
|
|
422
|
+
location = /500.html {
|
|
423
|
+
root /var/www/myapp/current/public;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Load Balancers
|
|
429
|
+
|
|
430
|
+
### Algoritmos
|
|
431
|
+
|
|
432
|
+
| Algoritmo | Descripción |
|
|
433
|
+
|-----------|-------------|
|
|
434
|
+
| Round Robin | Rotación secuencial |
|
|
435
|
+
| Least Connections | Servidor con menos conexiones |
|
|
436
|
+
| IP Hash | Mismo cliente siempre al mismo servidor |
|
|
437
|
+
| Weighted | Según capacidad del servidor |
|
|
438
|
+
|
|
439
|
+
### Nginx como Load Balancer
|
|
440
|
+
|
|
441
|
+
```nginx
|
|
442
|
+
upstream rails_cluster {
|
|
443
|
+
# Weighted round robin
|
|
444
|
+
server web1.example.com:3000 weight=3;
|
|
445
|
+
server web2.example.com:3000 weight=2;
|
|
446
|
+
server web3.example.com:3000 weight=1;
|
|
447
|
+
|
|
448
|
+
# Least connections
|
|
449
|
+
# least_conn;
|
|
450
|
+
|
|
451
|
+
# IP hash (sticky sessions)
|
|
452
|
+
# ip_hash;
|
|
453
|
+
|
|
454
|
+
# Keepalive connections
|
|
455
|
+
keepalive 32;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
server {
|
|
459
|
+
listen 80;
|
|
460
|
+
|
|
461
|
+
location / {
|
|
462
|
+
proxy_pass http://rails_cluster;
|
|
463
|
+
proxy_http_version 1.1;
|
|
464
|
+
proxy_set_header Connection "";
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Sticky Sessions
|
|
470
|
+
|
|
471
|
+
```nginx
|
|
472
|
+
upstream rails_cluster {
|
|
473
|
+
ip_hash; # Basado en IP
|
|
474
|
+
|
|
475
|
+
# O usar cookie
|
|
476
|
+
# sticky cookie srv_id expires=1h domain=.example.com path=/;
|
|
477
|
+
|
|
478
|
+
server web1:3000;
|
|
479
|
+
server web2:3000;
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Health Checks
|
|
484
|
+
|
|
485
|
+
```nginx
|
|
486
|
+
upstream rails_cluster {
|
|
487
|
+
server web1:3000 max_fails=3 fail_timeout=30s;
|
|
488
|
+
server web2:3000 max_fails=3 fail_timeout=30s;
|
|
489
|
+
server web3:3000 backup; # Solo si otros fallan
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## CDN (Content Delivery Network)
|
|
494
|
+
|
|
495
|
+
### Cómo funciona
|
|
496
|
+
|
|
497
|
+
```
|
|
498
|
+
Usuario en España
|
|
499
|
+
|
|
|
500
|
+
v
|
|
501
|
+
CDN Edge Server (Madrid)
|
|
502
|
+
|
|
|
503
|
+
| (cache miss)
|
|
504
|
+
v
|
|
505
|
+
Origin Server (USA)
|
|
506
|
+
|
|
|
507
|
+
| (respuesta)
|
|
508
|
+
v
|
|
509
|
+
CDN Edge (cachea)
|
|
510
|
+
|
|
|
511
|
+
v
|
|
512
|
+
Usuario (respuesta rápida)
|
|
513
|
+
|
|
514
|
+
# Siguiente request del mismo recurso:
|
|
515
|
+
Usuario -> CDN Edge (cache hit) -> Usuario
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Configuración en Rails
|
|
519
|
+
|
|
520
|
+
```ruby
|
|
521
|
+
# config/environments/production.rb
|
|
522
|
+
config.action_controller.asset_host = "https://cdn.example.com"
|
|
523
|
+
|
|
524
|
+
# O con ENV
|
|
525
|
+
config.action_controller.asset_host = ENV["CDN_HOST"]
|
|
526
|
+
|
|
527
|
+
# Conditional por request
|
|
528
|
+
config.action_controller.asset_host = proc { |source, request|
|
|
529
|
+
if request.ssl?
|
|
530
|
+
"https://cdn.example.com"
|
|
531
|
+
else
|
|
532
|
+
"http://cdn.example.com"
|
|
533
|
+
end
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Headers de cache para CDN
|
|
538
|
+
|
|
539
|
+
```ruby
|
|
540
|
+
# app/controllers/static_controller.rb
|
|
541
|
+
class StaticController < ApplicationController
|
|
542
|
+
def show
|
|
543
|
+
# Cache por 1 día en CDN, 1 hora en browser
|
|
544
|
+
expires_in 1.day, public: true, stale_while_revalidate: 1.hour
|
|
545
|
+
|
|
546
|
+
# Headers explícitos
|
|
547
|
+
response.headers["Cache-Control"] = "public, max-age=86400, s-maxage=604800"
|
|
548
|
+
response.headers["Surrogate-Control"] = "max-age=604800"
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
# Para assets (automático con Rails asset pipeline)
|
|
553
|
+
# config/environments/production.rb
|
|
554
|
+
config.public_file_server.headers = {
|
|
555
|
+
"Cache-Control" => "public, max-age=31536000"
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Invalidación de cache
|
|
560
|
+
|
|
561
|
+
```ruby
|
|
562
|
+
# Con Cloudflare
|
|
563
|
+
class CloudflareService
|
|
564
|
+
def self.purge_cache(urls)
|
|
565
|
+
conn = Faraday.new(url: "https://api.cloudflare.com")
|
|
566
|
+
conn.post("/client/v4/zones/#{ZONE_ID}/purge_cache") do |req|
|
|
567
|
+
req.headers["Authorization"] = "Bearer #{API_TOKEN}"
|
|
568
|
+
req.headers["Content-Type"] = "application/json"
|
|
569
|
+
req.body = { files: urls }.to_json
|
|
570
|
+
end
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
def self.purge_all
|
|
574
|
+
# Cuidado: puede ser lento
|
|
575
|
+
conn.post("/client/v4/zones/#{ZONE_ID}/purge_cache") do |req|
|
|
576
|
+
req.body = { purge_everything: true }.to_json
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# Uso
|
|
582
|
+
CloudflareService.purge_cache([
|
|
583
|
+
"https://example.com/assets/application.css",
|
|
584
|
+
"https://example.com/api/products.json"
|
|
585
|
+
])
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
## Firewalls
|
|
589
|
+
|
|
590
|
+
### iptables básico
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
# Ver reglas actuales
|
|
594
|
+
sudo iptables -L -n -v
|
|
595
|
+
|
|
596
|
+
# Permitir SSH
|
|
597
|
+
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
|
|
598
|
+
|
|
599
|
+
# Permitir HTTP/HTTPS
|
|
600
|
+
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
|
|
601
|
+
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
|
|
602
|
+
|
|
603
|
+
# Permitir localhost
|
|
604
|
+
sudo iptables -A INPUT -i lo -j ACCEPT
|
|
605
|
+
|
|
606
|
+
# Denegar todo lo demás
|
|
607
|
+
sudo iptables -A INPUT -j DROP
|
|
608
|
+
|
|
609
|
+
# Guardar reglas
|
|
610
|
+
sudo iptables-save > /etc/iptables/rules.v4
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### UFW (Ubuntu)
|
|
614
|
+
|
|
615
|
+
```bash
|
|
616
|
+
# Habilitar
|
|
617
|
+
sudo ufw enable
|
|
618
|
+
|
|
619
|
+
# Reglas básicas
|
|
620
|
+
sudo ufw allow ssh
|
|
621
|
+
sudo ufw allow 80/tcp
|
|
622
|
+
sudo ufw allow 443/tcp
|
|
623
|
+
|
|
624
|
+
# Permitir desde IP específica
|
|
625
|
+
sudo ufw allow from 192.168.1.100 to any port 5432
|
|
626
|
+
|
|
627
|
+
# Denegar
|
|
628
|
+
sudo ufw deny from 23.45.67.89
|
|
629
|
+
|
|
630
|
+
# Ver estado
|
|
631
|
+
sudo ufw status verbose
|
|
632
|
+
|
|
633
|
+
# Eliminar regla
|
|
634
|
+
sudo ufw delete allow 80/tcp
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### Security Groups (AWS)
|
|
638
|
+
|
|
639
|
+
```yaml
|
|
640
|
+
# Terraform example
|
|
641
|
+
resource "aws_security_group" "web" {
|
|
642
|
+
name = "web-servers"
|
|
643
|
+
description = "Security group for web servers"
|
|
644
|
+
|
|
645
|
+
# HTTP
|
|
646
|
+
ingress {
|
|
647
|
+
from_port = 80
|
|
648
|
+
to_port = 80
|
|
649
|
+
protocol = "tcp"
|
|
650
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
# HTTPS
|
|
654
|
+
ingress {
|
|
655
|
+
from_port = 443
|
|
656
|
+
to_port = 443
|
|
657
|
+
protocol = "tcp"
|
|
658
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
# SSH solo desde oficina
|
|
662
|
+
ingress {
|
|
663
|
+
from_port = 22
|
|
664
|
+
to_port = 22
|
|
665
|
+
protocol = "tcp"
|
|
666
|
+
cidr_blocks = ["203.0.113.0/24"]
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
# PostgreSQL solo interno
|
|
670
|
+
ingress {
|
|
671
|
+
from_port = 5432
|
|
672
|
+
to_port = 5432
|
|
673
|
+
protocol = "tcp"
|
|
674
|
+
security_groups = [aws_security_group.db.id]
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
egress {
|
|
678
|
+
from_port = 0
|
|
679
|
+
to_port = 0
|
|
680
|
+
protocol = "-1"
|
|
681
|
+
cidr_blocks = ["0.0.0.0/0"]
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
## Debugging de Red
|
|
687
|
+
|
|
688
|
+
### curl
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
# Request básico
|
|
692
|
+
curl https://example.com
|
|
693
|
+
|
|
694
|
+
# Ver headers de respuesta
|
|
695
|
+
curl -I https://example.com
|
|
696
|
+
|
|
697
|
+
# Ver request y response headers
|
|
698
|
+
curl -v https://example.com
|
|
699
|
+
|
|
700
|
+
# Con datos POST
|
|
701
|
+
curl -X POST https://api.example.com/users \
|
|
702
|
+
-H "Content-Type: application/json" \
|
|
703
|
+
-d '{"name": "John", "email": "john@example.com"}'
|
|
704
|
+
|
|
705
|
+
# Con autenticación
|
|
706
|
+
curl -H "Authorization: Bearer TOKEN" https://api.example.com/me
|
|
707
|
+
|
|
708
|
+
# Seguir redirects
|
|
709
|
+
curl -L https://example.com
|
|
710
|
+
|
|
711
|
+
# Timeout
|
|
712
|
+
curl --max-time 10 https://example.com
|
|
713
|
+
|
|
714
|
+
# Guardar cookies
|
|
715
|
+
curl -c cookies.txt https://example.com/login
|
|
716
|
+
curl -b cookies.txt https://example.com/dashboard
|
|
717
|
+
|
|
718
|
+
# Ver tiempos
|
|
719
|
+
curl -w "\nDNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
|
|
720
|
+
-o /dev/null -s https://example.com
|
|
721
|
+
|
|
722
|
+
# Ignorar SSL (solo desarrollo)
|
|
723
|
+
curl -k https://localhost:3000
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
### wget
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
# Descargar archivo
|
|
730
|
+
wget https://example.com/file.zip
|
|
731
|
+
|
|
732
|
+
# Descargar con nombre específico
|
|
733
|
+
wget -O myfile.zip https://example.com/file.zip
|
|
734
|
+
|
|
735
|
+
# Continuar descarga interrumpida
|
|
736
|
+
wget -c https://example.com/large-file.zip
|
|
737
|
+
|
|
738
|
+
# Spider mode (verificar enlaces)
|
|
739
|
+
wget --spider https://example.com
|
|
740
|
+
|
|
741
|
+
# Mirror sitio
|
|
742
|
+
wget --mirror --convert-links --page-requisites https://example.com
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### netstat/ss
|
|
746
|
+
|
|
747
|
+
```bash
|
|
748
|
+
# Ver puertos en escucha
|
|
749
|
+
netstat -tlnp
|
|
750
|
+
ss -tlnp
|
|
751
|
+
|
|
752
|
+
# Ver todas las conexiones
|
|
753
|
+
netstat -an
|
|
754
|
+
ss -an
|
|
755
|
+
|
|
756
|
+
# Conexiones establecidas
|
|
757
|
+
netstat -an | grep ESTABLISHED
|
|
758
|
+
|
|
759
|
+
# Conexiones por estado
|
|
760
|
+
ss -s
|
|
761
|
+
|
|
762
|
+
# Conexiones a puerto específico
|
|
763
|
+
netstat -an | grep :3000
|
|
764
|
+
ss -an | grep :3000
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### dig/nslookup
|
|
768
|
+
|
|
769
|
+
```bash
|
|
770
|
+
# Lookup básico
|
|
771
|
+
dig example.com
|
|
772
|
+
nslookup example.com
|
|
773
|
+
|
|
774
|
+
# Solo respuesta
|
|
775
|
+
dig +short example.com
|
|
776
|
+
|
|
777
|
+
# Registros específicos
|
|
778
|
+
dig example.com MX
|
|
779
|
+
dig example.com TXT
|
|
780
|
+
dig example.com NS
|
|
781
|
+
|
|
782
|
+
# Reverse lookup
|
|
783
|
+
dig -x 93.184.216.34
|
|
784
|
+
|
|
785
|
+
# Trace completo
|
|
786
|
+
dig +trace example.com
|
|
787
|
+
|
|
788
|
+
# Servidor DNS específico
|
|
789
|
+
dig @8.8.8.8 example.com
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
### Otros comandos útiles
|
|
793
|
+
|
|
794
|
+
```bash
|
|
795
|
+
# Ping
|
|
796
|
+
ping -c 4 example.com
|
|
797
|
+
|
|
798
|
+
# Traceroute
|
|
799
|
+
traceroute example.com
|
|
800
|
+
mtr example.com # Mejor visualización
|
|
801
|
+
|
|
802
|
+
# Ver interfaces de red
|
|
803
|
+
ifconfig
|
|
804
|
+
ip addr
|
|
805
|
+
|
|
806
|
+
# Ver tabla de rutas
|
|
807
|
+
route -n
|
|
808
|
+
ip route
|
|
809
|
+
|
|
810
|
+
# Test de puerto abierto
|
|
811
|
+
nc -zv example.com 443
|
|
812
|
+
telnet example.com 443
|
|
813
|
+
|
|
814
|
+
# tcpdump (captura de paquetes)
|
|
815
|
+
sudo tcpdump -i eth0 port 80
|
|
816
|
+
sudo tcpdump -i eth0 host example.com
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
## CORS en Rails
|
|
820
|
+
|
|
821
|
+
### Qué es CORS
|
|
822
|
+
|
|
823
|
+
```
|
|
824
|
+
Browser (example.com) -> API (api.example.com)
|
|
825
|
+
|
|
826
|
+
1. Browser envía preflight request (OPTIONS)
|
|
827
|
+
2. API responde con headers CORS permitidos
|
|
828
|
+
3. Browser envía request real si está permitido
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
### Configuración
|
|
832
|
+
|
|
833
|
+
```ruby
|
|
834
|
+
# Gemfile
|
|
835
|
+
gem "rack-cors"
|
|
836
|
+
|
|
837
|
+
# config/initializers/cors.rb
|
|
838
|
+
Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
|
839
|
+
allow do
|
|
840
|
+
# Orígenes permitidos
|
|
841
|
+
origins "example.com", "www.example.com", /\Ahttp:\/\/localhost:\d+\z/
|
|
842
|
+
|
|
843
|
+
resource "/api/*",
|
|
844
|
+
headers: :any,
|
|
845
|
+
methods: [:get, :post, :put, :patch, :delete, :options, :head],
|
|
846
|
+
credentials: true, # Permitir cookies
|
|
847
|
+
max_age: 86400 # Cache preflight por 1 día
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# API pública (sin credenciales)
|
|
851
|
+
allow do
|
|
852
|
+
origins "*"
|
|
853
|
+
|
|
854
|
+
resource "/public/*",
|
|
855
|
+
headers: :any,
|
|
856
|
+
methods: [:get, :options, :head]
|
|
857
|
+
end
|
|
858
|
+
end
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### Headers CORS
|
|
862
|
+
|
|
863
|
+
```ruby
|
|
864
|
+
# Manual en controller
|
|
865
|
+
class ApiController < ApplicationController
|
|
866
|
+
before_action :set_cors_headers
|
|
867
|
+
|
|
868
|
+
private
|
|
869
|
+
|
|
870
|
+
def set_cors_headers
|
|
871
|
+
response.headers["Access-Control-Allow-Origin"] = request.headers["Origin"] || "*"
|
|
872
|
+
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
|
|
873
|
+
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
|
|
874
|
+
response.headers["Access-Control-Allow-Credentials"] = "true"
|
|
875
|
+
response.headers["Access-Control-Max-Age"] = "86400"
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
def options
|
|
879
|
+
head :ok
|
|
880
|
+
end
|
|
881
|
+
end
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
### Debugging CORS
|
|
885
|
+
|
|
886
|
+
```bash
|
|
887
|
+
# Simular preflight
|
|
888
|
+
curl -X OPTIONS https://api.example.com/resource \
|
|
889
|
+
-H "Origin: https://example.com" \
|
|
890
|
+
-H "Access-Control-Request-Method: POST" \
|
|
891
|
+
-H "Access-Control-Request-Headers: Content-Type" \
|
|
892
|
+
-v
|
|
893
|
+
|
|
894
|
+
# Verificar headers de respuesta
|
|
895
|
+
Access-Control-Allow-Origin: https://example.com
|
|
896
|
+
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
|
|
897
|
+
Access-Control-Allow-Headers: Content-Type
|
|
898
|
+
Access-Control-Allow-Credentials: true
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
### Errores comunes
|
|
902
|
+
|
|
903
|
+
```javascript
|
|
904
|
+
// Error en browser
|
|
905
|
+
// Access to XMLHttpRequest at 'https://api.example.com' from origin
|
|
906
|
+
// 'https://example.com' has been blocked by CORS policy
|
|
907
|
+
|
|
908
|
+
// Causas comunes:
|
|
909
|
+
// 1. Origin no está en lista permitida
|
|
910
|
+
// 2. Método no permitido
|
|
911
|
+
// 3. Header no permitido
|
|
912
|
+
// 4. credentials: true pero Allow-Origin es "*"
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
## Checklist de Networking
|
|
916
|
+
|
|
917
|
+
### Antes de deploy
|
|
918
|
+
|
|
919
|
+
- [ ] DNS configurado correctamente
|
|
920
|
+
- [ ] Certificado SSL válido
|
|
921
|
+
- [ ] Firewall permite puertos necesarios
|
|
922
|
+
- [ ] CORS configurado si hay API
|
|
923
|
+
- [ ] CDN configurado para assets
|
|
924
|
+
|
|
925
|
+
### Debugging
|
|
926
|
+
|
|
927
|
+
- [ ] ¿DNS resuelve correctamente? (dig)
|
|
928
|
+
- [ ] ¿Puerto está abierto? (nc, telnet)
|
|
929
|
+
- [ ] ¿Servidor responde? (curl -v)
|
|
930
|
+
- [ ] ¿Headers correctos? (curl -I)
|
|
931
|
+
- [ ] ¿SSL válido? (openssl s_client)
|
|
932
|
+
- [ ] ¿CORS correcto? (browser console)
|