Webhook Forge is a lightweight server for receiving webhook requests and creating flag files upon successful processing.
- Features
- Installation
- Configuration
- API Endpoints
- Usage Examples
- Deployment
- Project Structure
- License
- Simple API for creating and managing webhooks
- Secure token verification for authorizing calls
- Creation of flag files upon successful webhook invocation
- Easy configuration via JSON file
- Structured logging with file output and rotation
- Support for deployment behind a reverse proxy in a subdirectory
git clone git@github.com:mvandrew/webhook-forge.git
cd webhook-forge
go build -o webhook-forge ./cmd/serverThe project includes a Makefile with various useful commands for building and running the application:
# Build both server and admin token generator
make build
# Build only the server
make build-server
# Build only the admin token generator
make build-admin-token
# Run the server
make run-server
# Generate admin token
make tokenThe configuration file is automatically created on first run in the config/config.json directory. You can modify the following parameters:
{
"server": {
"host": "127.0.0.1",
"port": 8080,
"base_path": "",
"admin_token": "admin-token"
},
"hooks": {
"storage_path": "data/hooks.json",
"flags_dir": "data/flags"
},
"log": {
"level": "info",
"format": "json",
"file_path": "logs/webhook-forge.log",
"max_size": 100,
"max_backups": 5
}
}To set up the application, create your own configuration file based on the example:
cp config/config.example.json config/config.jsonThen edit the config/config.json file according to your requirements. The example configuration file is tracked in git, while your local configuration file is ignored.
The logging system supports output to files with automatic rotation to prevent excessive disk usage:
level: Sets the minimum log level ("debug", "info", "warn", "error", "fatal")format: Log format ("json" or "text")file_path: Path to the log file (if omitted, logs go to stdout)max_size: Maximum size of each log file in megabytes before rotationmax_backups: Maximum number of rotated log files to keep
When log files reach the maximum size, they are automatically rotated, and old files are named with a numeric suffix (e.g., webhook-forge.log.1, webhook-forge.log.2). Once the number of backups exceeds max_backups, the oldest files are removed.
For security reasons, you should generate a random admin token instead of using the default value. Use the provided admin token generator tool:
make tokenThis will generate a secure random token and ask for confirmation before saving it to your configuration file. If you already have a token in your configuration, you'll be shown both the current and new tokens before being asked to confirm the replacement.
If you're running the webhook-forge server behind a reverse proxy (like Nginx) at a subdirectory, you can use the base_path setting:
{
"server": {
"host": "127.0.0.1",
"port": 8080,
"base_path": "/hooks"
}
}This will make all routes available at /hooks/* (e.g., /hooks/api/hooks, /hooks/webhook/my-hook), which can then be properly proxied.
server {
listen 80;
server_name example.com;
location /hooks/ {
proxy_pass http://127.0.0.1:8080/hooks/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}For enhanced security, you can restrict access to webhook management endpoints based on IP addresses while keeping webhook invocation endpoints accessible from anywhere. This is particularly useful for production environments.
server {
listen 80;
server_name example.com;
# Allow webhook invocation from anywhere
location ~ ^/hooks/webhook/ {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Restrict webhook management API to specific IPs
location ~ ^/hooks/api/ {
# Allow only specific IP addresses
allow 192.168.1.100; # Admin workstation
allow 10.0.0.0/24; # Internal network
deny all; # Deny everyone else
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}GET /api/hooks- List all webhooks (requires admin token)GET /api/hooks/{id}- Get information about a specific webhook (requires admin token)POST /api/hooks- Create a new webhook (requires admin token)PUT /api/hooks/{id}- Update an existing webhook (requires admin token)DELETE /api/hooks/{id}- Delete a webhook (requires admin token)
Note: If you've configured base_path, prepend it to these endpoints (e.g., /hooks/api/hooks).
POST /webhook/{id}?token=your-secret-token- Trigger a webhook, creating the configured flag file
All API endpoints (GET, POST, PUT, DELETE) require the Authorization: Bearer <token> header for authentication. The token must match the value defined in the server configuration.
All API responses follow a consistent format:
{
"success": true|false,
"data": {/* returned data object */},
"errors": ["error message 1", "error message 2"]
}When an operation is successful, the success field is true and the data field contains the result. When an error occurs, success is false and the errors field contains error messages.
curl -X GET http://localhost:8080/api/hooks \
-H "Authorization: Bearer admin-token"curl -X POST http://localhost:8080/api/hooks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer admin-token" \
-d '{
"id": "my-webhook",
"name": "My Webhook",
"description": "Webhook for my project",
"token": "your-secret-token",
"flag_file": "my-project/flag.txt",
"enabled": true
}'Note: The token field is optional. If not provided, a secure token will be automatically generated.
curl -X POST "http://localhost:8080/webhook/my-webhook?token=your-secret-token"After a successful invocation, the file will be created in the data/flags/my-project/flag.txt directory.
You can run webhook-forge as a system service on Linux using systemd. Create a service file at /etc/systemd/system/webhook-forge.service:
[Unit]
Description=Webhook Forge Service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=youruser
WorkingDirectory=/path/to/webhook-forge
ExecStart=/path/to/webhook-forge/bin/webhook-forge
[Install]
WantedBy=multi-user.targetReplace youruser with the appropriate user and adjust the paths accordingly.
Enable and start the service:
sudo systemctl enable webhook-forge
sudo systemctl start webhook-forgeCheck service status:
sudo systemctl status webhook-forgeView logs:
sudo journalctl -u webhook-forgeThe project includes several scripts in the scripts/ directory to simplify service installation and management.
To install Webhook Forge as a systemd service:
sudo ./scripts/install-service.shThis script supports the following command-line options:
-h, --help: Show help message-n, --name NAME: Name of the service (default: "webhook-forge")-u, --user USER: User to run the service as (default: current user)-d, --dir DIRECTORY: Installation directory (default: current directory)-c, --config PATH: Path to config file (default: "INSTALL_DIR/config/config.json")-e, --executable PATH: Path to executable (default: "INSTALL_DIR/bin/server")
Example with custom settings:
sudo ./scripts/install-service.sh --name my-webhook --user webuser --executable /opt/webhook-forge/bin/webhook-forgeTo uninstall the service:
sudo ./scripts/uninstall-service.shFor custom service name, use the --name option:
sudo ./scripts/uninstall-service.sh --name my-webhookTo install Webhook Forge as a Docker service managed by systemd:
sudo ./scripts/install-docker-service.shThis script supports the following command-line options:
-h, --help: Show help message-n, --name NAME: Name of the service (default: "webhook-forge-docker")-d, --dir DIRECTORY: Installation directory (default: current directory)-f, --file FILE: Path to docker-compose file (default: "INSTALL_DIR/docker-compose.prod.yml")-u, --user USER: User to run the service as (default: current user)
Example with custom settings:
sudo ./scripts/install-docker-service.sh --name my-webhook-docker --file /opt/webhook-forge/docker-compose.ymlTo uninstall the Docker service:
sudo ./scripts/uninstall-docker-service.shFor custom service name, use the --name option:
sudo ./scripts/uninstall-docker-service.sh --name my-webhook-dockerBuild the Docker image:
make docker-buildRun the container:
make docker-runOr for local-only access:
make docker-run-localStop the container:
make docker-stopCreate a docker-compose.yml file:
version: '3'
services:
webhook-forge:
image: msav/webhook-forge:latest
container_name: webhook-forge
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./config:/app/config
- ./data:/app/data
- ./logs:/app/logsStart the service:
docker-compose up -dFor production deployment with the provided production configuration:
make docker-compose-prod-upTo stop the service:
make docker-compose-prod-downThe webhook-forge Docker image is available on Docker Hub: https://hub.docker.com/r/msav/webhook-forge
Pull the latest image:
docker pull msav/webhook-forge:latestThe project is organized according to clean architecture principles:
cmd/server- Application entry pointcmd/admin_token_generator- Utility for generating admin tokensinternal/api- HTTP handlersinternal/config- Application configurationinternal/domain- Data models and interfacesinternal/service- Business logicinternal/storage- Data storagepkg/logger- Loggingpkg/validator- Data validationscripts- Service installation and management scripts
GNU General Public License v3.0