diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 77f3d40bcd..4c15e03734 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,6 +17,10 @@ jobs:
         with:
           go-version: ${{ matrix.go-version }}
 
+      - uses: bufbuild/buf-setup-action@v1
+        with:
+          version: "1.34.0"
+
       - name: Checkout code
         uses: actions/checkout@v4
 
@@ -55,3 +59,7 @@ jobs:
         env:
           PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
         run: misc/scripts/release_packagecloud.sh
+
+      - uses: bufbuild/buf-push-action@v1
+        with:
+          buf_token: ${{ secrets.BUF_TOKEN }}
diff --git a/buf.yaml b/buf.yaml
new file mode 100644
index 0000000000..60aa397035
--- /dev/null
+++ b/buf.yaml
@@ -0,0 +1,18 @@
+version: v2
+modules:
+  - path: internal/apiproto
+    name: buf.build/centrifugo/apiproto
+    excludes:
+      - internal/apiproto/swagger
+  - path: internal/proxyproto
+    name: buf.build/centrifugo/proxyproto
+  - path: internal/unigrpc/unistream
+    name: buf.build/centrifugo/unistream
+lint:
+  use:
+    - DEFAULT
+  ignore:
+    - internal/apiproto/swagger/api.swagger.proto
+breaking:
+  use:
+    - FILE
diff --git a/internal/apiproto/readme.md b/internal/apiproto/readme.md
index ba9aa7607c..91e3a4b894 100644
--- a/internal/apiproto/readme.md
+++ b/internal/apiproto/readme.md
@@ -1,54 +1 @@
-## Generate HTTP API libraries from swagger spec: 
-
-```
-git clone --depth 1 -b master https://github.com/swagger-api/swagger-codegen.git
-cd swagger-codegen
-cp /path/to/api.swagger.json ./api.swagger.json
-```
-
-### Go library:
-
-```
-./run-in-docker.sh generate -i api.swagger.json -l go -o /gen/out/go-centrifugo -DpackageName=centrifugo
-ls out/go-centrifugo
-```
-
-Then:
-
-```go
-package main
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"time"
-
-	"test_project/centrifugo"
-)
-
-func main() {
-	httpClient := &http.Client{Transport: &http.Transport{
-		MaxIdleConnsPerHost: 100,
-	}, Timeout: time.Second}
-	client := centrifugo.NewAPIClient(&centrifugo.Configuration{
-		BasePath:      "http://localhost:8000/api",
-		DefaultHeader: map[string]string{"Authorization": "apikey "},
-		HTTPClient:    httpClient,
-	})
-	reply, resp, err := client.PublicationApi.CentrifugoApiPublish(context.Background(), centrifugo.PublishRequest{
-		Channel: "test",
-		Data:    map[string]string{},
-	})
-	if err != nil {
-		panic(err)
-	}
-	if resp.StatusCode != 200 {
-		panic(resp.StatusCode)
-	}
-	if reply.Error_ != nil {
-		panic(reply.Error_.Message)
-	}
-	fmt.Println("ok")
-}
-```
+Centrifugo server API Protobuf definitions.
diff --git a/internal/apiproto/api.swagger.json b/internal/apiproto/swagger/api.swagger.json
similarity index 99%
rename from internal/apiproto/api.swagger.json
rename to internal/apiproto/swagger/api.swagger.json
index 872c215454..22f1411a2a 100644
--- a/internal/apiproto/api.swagger.json
+++ b/internal/apiproto/swagger/api.swagger.json
@@ -32,9 +32,6 @@
     {
       "name": "push notification"
     },
-    {
-      "name": "rate limiting"
-    },
     {
       "name": "batch"
     }
diff --git a/internal/apiproto/api.swagger.proto b/internal/apiproto/swagger/api.swagger.proto
similarity index 99%
rename from internal/apiproto/api.swagger.proto
rename to internal/apiproto/swagger/api.swagger.proto
index 7a9f66ec07..e966f19ffd 100644
--- a/internal/apiproto/api.swagger.proto
+++ b/internal/apiproto/swagger/api.swagger.proto
@@ -48,9 +48,6 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
     {
       name: "push notification"
     },
-    {
-      name: "rate limiting"
-    },
     {
       name: "batch"
     }
diff --git a/internal/apiproto/generate_swagger.sh b/internal/apiproto/swagger/generate_swagger.sh
old mode 100755
new mode 100644
similarity index 100%
rename from internal/apiproto/generate_swagger.sh
rename to internal/apiproto/swagger/generate_swagger.sh
diff --git a/internal/apiproto/google/api/annotations.proto b/internal/apiproto/swagger/google/api/annotations.proto
similarity index 100%
rename from internal/apiproto/google/api/annotations.proto
rename to internal/apiproto/swagger/google/api/annotations.proto
diff --git a/internal/apiproto/google/api/http.proto b/internal/apiproto/swagger/google/api/http.proto
similarity index 100%
rename from internal/apiproto/google/api/http.proto
rename to internal/apiproto/swagger/google/api/http.proto
diff --git a/internal/apiproto/protoc-gen-openapiv2/options/annotations.proto b/internal/apiproto/swagger/protoc-gen-openapiv2/options/annotations.proto
similarity index 100%
rename from internal/apiproto/protoc-gen-openapiv2/options/annotations.proto
rename to internal/apiproto/swagger/protoc-gen-openapiv2/options/annotations.proto
diff --git a/internal/apiproto/protoc-gen-openapiv2/options/openapiv2.proto b/internal/apiproto/swagger/protoc-gen-openapiv2/options/openapiv2.proto
similarity index 100%
rename from internal/apiproto/protoc-gen-openapiv2/options/openapiv2.proto
rename to internal/apiproto/swagger/protoc-gen-openapiv2/options/openapiv2.proto
diff --git a/misc/scripts/generate.sh b/misc/scripts/generate.sh
index 93d386ba31..3569f04008 100644
--- a/misc/scripts/generate.sh
+++ b/misc/scripts/generate.sh
@@ -8,6 +8,9 @@ fi
 
 cd internal/apiproto
 bash generate.sh
+cd -
+
+cd internal/apiproto/swagger
 bash generate_swagger.sh
 cd -
 
diff --git a/misc/scripts/update_swagger_web.sh b/misc/scripts/update_swagger_web.sh
index 8ba1431f58..64f770478a 100755
--- a/misc/scripts/update_swagger_web.sh
+++ b/misc/scripts/update_swagger_web.sh
@@ -14,7 +14,7 @@ cleanup_exit() {
 }
 
 git clone -c advice.detachedHead=false --depth 1 --branch v4.18.1 --single-branch https://github.com/swagger-api/swagger-ui.git "$TMP_WORK_DIR"
-cp internal/apiproto/api.swagger.json "$TMP_WORK_DIR"/dist/swagger.json
+cp internal/apiproto/swagger/api.swagger.json "$TMP_WORK_DIR"/dist/swagger.json
 
 oldString="https://petstore.swagger.io/v2/"
 newString="./"