| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| default.env | ||
| deploy.sh | ||
| Dockerfile | ||
| example.png | ||
| LICENSE | ||
| README.md | ||
| rust-toolchain | ||
Forgejo Shield
A simple bot protection for self-hosted Forgejo instances. Readme more about it on this blog post.
In collaboration with the reverse proxy Caddy, every request to Forgejo will first be sent to this "forgejo-shield". It can then either let it through or shield it by presenting a button that a user has to click to set a cookie.
Note that forgejo-shield does not receive the body of the original request, it only acts as a bouncer: either allowing the request to go as normal by answering "200 OK" or providing a replacement answer.
Requests that pass through
Some requests are always allowed to continue their normal journey:
- static assets at
/assets/* - at most two levels deep, like
/,/fooand/foo/bar - git endpoints, like
/foo/bar.git/baz/boom
The flow is described below:
sequenceDiagram
Client ->>+ Caddy: GET /foo
Caddy ->>+ Shield: GET /<br>X-Forwarded-Method: GET<br>X-Forwarded-Uri: /foo
Shield -->>- Caddy: 200 OK
Caddy ->>+ Forgejo: GET /foo
Forgejo -->>- Caddy: response
Caddy -->>- Client: response
Requests that are shielded
Anything else will require the right cookie to be present. When not, the user will first receive a HTML form with a button to POST to another page, so that the cookie can be set.
sequenceDiagram
%% part 1
Client ->>+ Caddy: GET /bar
Caddy ->>+ Shield: GET /<br>X-Forwarded-Method: GET<br>X-Forwarded-Uri: /bar
Shield -->>- Caddy: 403 Forbidden<br>HTML form to continue
Caddy -->>- Client: response
sequenceDiagram
%% part 2
Client ->>+ Caddy: POST /__forgejo-shield/bar
Caddy ->>+ Shield: GET /<br>X-Forwarded-Method: POST<br>X-Forwarded-Uri: /__forgejo-shield/bar
Shield -->>- Caddy: 303 See Other<br>Set-Cookie: __FORGEJO-SHIELD=yada<br>Location: /bar
Caddy -->>- Client: response
%% part 3
Client ->>+ Caddy: GET /bar<br>Cookie: __FORGEJO-SHIELD=yada
Caddy ->>+ Shield: GET /<br>X-Forwarded-Method: GET<br>X-Forwarded-Uri: /bar<br>Cookie: __FORGEJO-SHIELD=yada
Shield -->>- Caddy: 200 OK
Caddy ->>+ Forgejo: GET /bar
Forgejo -->>- Caddy: response
Caddy -->>- Client: response
The value of the cookie is randomly chosen at every startup.
Deploy
- build the container image with
podman build . -t forgejo-shield - run the container as "forgejo-shield" and make sure it's accessible from the Caddy container
- configure your Caddyfile with a
forward_authblock, like this:git.sitegui.dev { forward_auth forgejo-shield:8080 { uri / } reverse_proxy forgejo:3000 }
Deploy at sitegui.dev
Set git alias with:
git config alias.deploy '!git push && ssh -4 sitegui@ssh.sitegui.dev ./deploy sitegui/forgejo-shield'
then simply run git deploy to push and deploy.
