Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions site/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default defineConfig({
root: { label: 'English', lang: 'en' },
'zh-cn': { label: '简体中文', lang: 'zh-CN' },
ja: { label: '日本語', lang: 'ja' },
es: { label: 'Español', lang: 'es' },
},
logo: {
light: './src/assets/logo-light.svg',
Expand Down Expand Up @@ -103,9 +104,9 @@ export default defineConfig({
// Autogenerated from the content dirs — new pages appear automatically,
// ordered by each page's `sidebar.order` frontmatter.
sidebar: [
{ label: 'Guide', translations: { 'zh-CN': '指南', ja: 'ガイド' }, items: [{ autogenerate: { directory: 'guide' } }] },
{ label: 'Middleware', translations: { 'zh-CN': '中间件', ja: 'ミドルウェア' }, items: [{ autogenerate: { directory: 'middleware' } }] },
{ label: 'Cookbook', translations: { 'zh-CN': '示例', ja: 'クックブック' }, items: [{ autogenerate: { directory: 'cookbook' } }] },
{ label: 'Guide', translations: { 'zh-CN': '指南', ja: 'ガイド', es: 'Guía' }, items: [{ autogenerate: { directory: 'guide' } }] },
{ label: 'Middleware', translations: { 'zh-CN': '中间件', ja: 'ミドルウェア', es: 'Middleware' }, items: [{ autogenerate: { directory: 'middleware' } }] },
{ label: 'Cookbook', translations: { 'zh-CN': '示例', ja: 'クックブック', es: 'Recetario' }, items: [{ autogenerate: { directory: 'cookbook' } }] },
],
// tune the built-in code theme toward our terminal palette
expressiveCode: { themes: ['github-dark', 'github-light'] },
Expand Down
110 changes: 110 additions & 0 deletions site/src/content/docs/es/cookbook/auto-tls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: Auto TLS
description: Obtén y renueva automáticamente certificados TLS desde Let's Encrypt.
sidebar:
order: 3
---

Esta receta obtiene automáticamente certificados TLS para un dominio desde Let's Encrypt.
Configura un `StartConfig` con el `TLSConfig` del manager autocert y escucha en el
puerto `443`.

Abre `https://<DOMAIN>`. Si todo está configurado correctamente, deberías ver
un mensaje de bienvenida servido sobre TLS.

:::tip
- Para mayor seguridad, especifica una host policy en el manager autocert.
- Cachea certificados para evitar alcanzar los [rate limits de Let's Encrypt](https://letsencrypt.org/docs/rate-limits).
- Para redirigir tráfico HTTP a HTTPS, usa el [middleware redirect](/es/middleware/redirect/#https-redirect).
:::

## Servidor

```go
package main

import (
"context"
"crypto/tls"
"errors"
"log/slog"
"net/http"
"os"

"golang.org/x/crypto/acme"

"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
"golang.org/x/crypto/acme/autocert"
)

func main() {
e := echo.New()
e.Logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))

e.Use(middleware.Recover())
e.Use(middleware.RequestLogger())

e.GET("/", func(c *echo.Context) error {
return c.HTML(http.StatusOK, `
<h1>Welcome to Echo!</h1>
<h3>TLS certificates automatically installed from Let's Encrypt :)</h3>
`)
})

m := &autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.com", "www.example.com"),
// Cache certificates to avoid issues with rate limits (https://letsencrypt.org/docs/rate-limits)
Cache: autocert.DirCache("/var/www/.cache"),
// Email: "[email protected]", // optional but recommended
}

sc := echo.StartConfig{
Address: ":443",
TLSConfig: m.TLSConfig(),
}
if err := sc.Start(context.Background(), e); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}
```

## Usar un servidor HTTP personalizado

Si necesitas control total sobre `http.Server`, conecta el manager autocert a un
`tls.Config` personalizado:

```go
func customHTTPServer() {
e := echo.New()
e.Use(middleware.Recover())
e.Use(middleware.RequestLogger())
e.GET("/", func(c *echo.Context) error {
return c.HTML(http.StatusOK, `
<h1>Welcome to Echo!</h1>
<h3>TLS certificates automatically installed from Let's Encrypt :)</h3>
`)
})

autoTLSManager := autocert.Manager{
Prompt: autocert.AcceptTOS,
// Cache certificates to avoid issues with rate limits (https://letsencrypt.org/docs/rate-limits)
Cache: autocert.DirCache("/var/www/.cache"),
//HostPolicy: autocert.HostWhitelist("<DOMAIN>"),
}
s := http.Server{
Addr: ":443",
Handler: e, // set Echo as handler
TLSConfig: &tls.Config{
//Certificates: nil, // <-- s.ListenAndServeTLS will populate this field
GetCertificate: autoTLSManager.GetCertificate,
NextProtos: []string{acme.ALPNProto},
},
//ReadTimeout: 30 * time.Second, // use custom timeouts
}
if err := s.ListenAndServeTLS("", ""); err != nil && !errors.Is(err, http.ErrServerClosed) {
e.Logger.Error("failed to start server", "error", err)
}
}
```
120 changes: 120 additions & 0 deletions site/src/content/docs/es/cookbook/cors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
title: CORS
description: Habilita Cross-Origin Resource Sharing con una allow list o una función de origin personalizada.
sidebar:
order: 4
---

El [middleware CORS](/es/middleware/cors/) controla qué origins pueden acceder a tu API.
Puedes pasar una lista fija de origins permitidos o proporcionar una función que decida
por request.

## Allow list de origins

Pasa los origins permitidos directamente a `middleware.CORS`.

```go
package main

import (
"context"
"net/http"

"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
)

var (
users = []string{"Joe", "Veer", "Zion"}
)

func getUsers(c *echo.Context) error {
return c.JSON(http.StatusOK, users)
}

func main() {
e := echo.New()
e.Use(middleware.RequestLogger())
e.Use(middleware.Recover())

// CORS default
// Allows requests from any origin wth GET, HEAD, PUT, POST or DELETE method.
// e.Use(middleware.CORS("*"))

// CORS restricted
// Allows requests from any `https://labstack.com` or `https://labstack.net` origin
e.Use(middleware.CORS("https://labstack.com", "https://labstack.net"))

e.GET("/api/users", getUsers)

sc := echo.StartConfig{Address: ":1323"}
if err := sc.Start(context.Background(), e); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}
```

## Función de origin personalizada

Para policies dinámicas, usa `CORSWithConfig` con `UnsafeAllowOriginFunc`. La
función recibe el contexto del request y el origin, y devuelve el origin que se debe
reflejar, si el request está permitido y un error opcional.

```go
package main

import (
"context"
"net/http"
"strings"

"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
)

var (
users = []string{"Joe", "Veer", "Zion"}
)

func getUsers(c *echo.Context) error {
return c.JSON(http.StatusOK, users)
}

// allowOrigin takes the origin as an argument and returns:
// - origin to add to the response Access-Control-Allow-Origin header
// - whether the request is allowed or not
// - an optional error. this will stop handler chain execution and return an error response.
//
// return origin, true, err // blocks request with error
// return origin, true, nil // allows CSRF request through
// return origin, false, nil // falls back to legacy token logic
func allowOrigin(c *echo.Context, origin string) (string, bool, error) {
// In this example we use a naive suffix check but we can imagine various
// kind of custom logic. For example, an external datasource could be used
// to maintain the list of allowed origins.
if strings.HasSuffix(origin, ".example.com") {
return origin, true, nil
}
return "", false, nil
}

func main() {
e := echo.New()
e.Use(middleware.RequestLogger())
e.Use(middleware.Recover())

// CORS restricted with a custom function to allow origins
// and with the GET, PUT, POST or DELETE methods allowed.
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
UnsafeAllowOriginFunc: allowOrigin,
AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
}))

e.GET("/api/users", getUsers)

sc := echo.StartConfig{Address: ":1323"}
if err := sc.Start(context.Background(), e); err != nil {
e.Logger.Error("failed to start server", "error", err)
}
}
```
Loading
Loading