Go HTTPS reverse proxy: auto Let’s Encrypt, optional mTLS, HTTP/2, REST & gRPC-Web.
10K+
Add automatic HTTPS to any web app, API, or gRPC service in 2 minutes. No Nginx config, no manual certificates — just point your domain and run.
You have a web app running on localhost:3000. You want:
This reverse proxy handles all of that automatically.
Your App (localhost:3000) + This Proxy = https://yourdomain.com (automatic cert)
✅ Primary use case:
✅ Advanced use case (centralized reverse proxy):
api.yourdomain.com → Heroku app, web.yourdomain.com → Vercel, etc.example.com → 203.0.113.10)You have a Node.js API running on port 3000 in your DigitalOcean droplet. Want it accessible via https://myapp.com with automatic SSL:
Using Docker with environment variables:
docker run -d \
--name reverseproxy \
-p 80:80 -p 443:443 -p 8081:8081 \
-e DOMAIN=myapp.com \
-e BACKEND_HOST=localhost \
-e BACKEND_PORT=3000 \
-e BACKEND_SCHEME=http \
-v reverseproxy-certs:/app/certs \
--network host \
janmbaco/go-reverseproxy-ssl:v3
That's it! Visit https://myapp.com — certificate is automatically issued by Let's Encrypt.
How it works:
myapp.com → Your VPS IP (203.0.113.10)/app/certshttp://localhost:3000Platform-specific notes:
--network host or backend service IPlocalhost with service name (see Example 3)You have three services and want separate subdomains with automatic HTTPS — no config.json needed:
www.myapp.comapi.myapp.comapp.myapp.comUsing Docker with environment variables:
docker run -d \
--name reverseproxy \
-p 80:80 -p 443:443 -p 8081:8081 \
-e WWW_DOMAIN=www.myapp.com \
-e WWW_BACKEND=localhost:3000 \
-e API_DOMAIN=api.myapp.com \
-e API_BACKEND=localhost:8080 \
-e APP_DOMAIN=app.myapp.com \
-e APP_BACKEND=localhost:5000 \
-v reverseproxy-certs:/app/certs \
--network host \
janmbaco/go-reverseproxy-ssl:v3
Result:
https://www.myapp.com → React app (automatic cert)https://api.myapp.com → Express API (automatic cert)https://app.myapp.com → Admin dashboard (automatic cert)Backend format:
host:port (defaults to HTTP)host:port:https (for HTTPS backends)Examples:
-e WWW_BACKEND=frontend-service:3000 # HTTP backend
-e API_BACKEND=api.herokuapp.com:443:https # HTTPS backend
-e APP_BACKEND=172.17.0.1:5000 # Docker bridge IP
Same setup as Example 2, but using Docker Compose with custom config.json for advanced features:
You have:
www.myapp.comapi.myapp.comadmin.myapp.comdocker-compose.yml:
version: "3.9"
services:
reverseproxy:
image: janmbaco/go-reverseproxy-ssl:v3
ports:
- "80:80"
- "443:443"
- "8081:8081"
volumes:
- ./config.json:/app/config/config.json:ro
- certs:/app/certs
networks: [app]
frontend:
image: my-frontend:latest
expose: ["3000"]
networks: [app]
api:
image: my-api:latest
expose: ["8080"]
networks: [app]
admin:
image: my-admin:latest
expose: ["5000"]
networks: [app]
networks:
app:
volumes:
certs:
config.json:
{
"web_virtual_hosts": [
{
"from": "www.myapp.com",
"scheme": "http",
"host_name": "frontend",
"port": 3000
},
{
"from": "api.myapp.com",
"scheme": "http",
"host_name": "api",
"port": 8080
},
{
"from": "admin.myapp.com",
"scheme": "http",
"host_name": "admin",
"port": 5000
}
],
"default_host": "www.myapp.com",
"reverse_proxy_port": ":443",
"config_ui_port": ":8081"
}
Run: docker-compose up -d
Result:
https://www.myapp.com → frontend (automatic cert)https://api.myapp.com → API (automatic cert)https://admin.myapp.com → admin panel (automatic cert)Backend gRPC service on port 9090, expose as https://grpc.myapp.com for browser access:
Simple config (transparent mode - proxies all services/methods):
{
"grpc_web_virtual_hosts": [
{
"from": "grpc.myapp.com",
"scheme": "http",
"host_name": "grpc-service",
"port": 9090,
"grpc_web_proxy": {
"is_transparent_server": true,
"allow_all_origins": true
}
}
],
"default_host": "grpc.myapp.com",
"reverse_proxy_port": ":443"
}
Advanced config (selective service/method proxying):
{
"grpc_web_virtual_hosts": [
{
"from": "grpc.myapp.com",
"scheme": "http",
"host_name": "grpc-service",
"port": 9090,
"grpc_web_proxy": {
"grpc_services": {
"hello.HelloService": ["SayHello", "ServerStreamingChat"],
"user.UserService": ["GetUser", "UpdateUser"]
},
"is_transparent_server": false,
"authority": "grpc-service:9090",
"allow_all_origins": false,
"allowed_origins": ["https://myapp.com"]
}
}
],
"default_host": "grpc.myapp.com",
"reverse_proxy_port": ":443"
}
JavaScript gRPC-Web client:
const client = new GreeterClient('https://grpc.myapp.com');
Note: The
grpc_web_proxyfield is required for gRPC-Web virtual hosts. Setis_transparent_server: trueto proxy all services automatically, or set it tofalseand specifygrpc_servicesfor fine-grained control.
Instead of editing JSON, use the built-in web interface:
http://localhost:8081 (or your server IP:8081)example.commy-app3000httpUI Features:
Security: Bind to
127.0.0.1:8081for localhost-only access, or put behind authentication.
Minimal config:
{
"web_virtual_hosts": [
{
"from": "myapp.com",
"scheme": "http",
"host_name": "localhost",
"port": 3000
}
],
"default_host": "myapp.com",
"reverse_proxy_port": ":443"
}
Docker command:
docker run -d \
-p 80:80 -p 443:443 \
-e DOMAIN=myapp.com \
-e BACKEND_HOST=host.docker.internal \
-e BACKEND_PORT=3000 \
-v certs:/app/certs \
janmbaco/go-reverseproxy-ssl:v3
Verify:
curl -I https://myapp.com # Should return 200 with Let's Encrypt cert
Scenario: Express API (port 8080) + Next.js (port 3000)
docker-compose.yml:
services:
proxy:
image: janmbaco/go-reverseproxy-ssl:v3
ports: ["80:80", "443:443"]
volumes:
- ./config.json:/app/config/config.json:ro
- certs:/app/certs
networks: [backend]
api:
build: ./api
expose: ["8080"]
networks: [backend]
web:
build: ./web
expose: ["3000"]
networks: [backend]
networks:
backend:
volumes:
certs:
config.json:
{
"web_virtual_hosts": [
{"from": "api.example.com", "host_name": "api", "port": 8080, "scheme": "http"},
{"from": "www.example.com", "host_name": "web", "port": 3000, "scheme": "http"}
],
"default_host": "www.example.com",
"reverse_proxy_port": ":443"
}
Result:
https://www.example.comhttps://api.example.comWhen you need this:
config.json:
{
"web_virtual_hosts": [
{
"from": "secure.internal.com",
"scheme": "http",
"host_name": "backend",
"port": 8080,
"server_certificate": {
"certificate_path": "/certs/internal.pem",
"private_key_path": "/certs/internal-key.pem"
}
}
],
"default_host": "secure.internal.com",
"reverse_proxy_port": ":443"
}
Docker mount:
docker run -d \
-p 80:80 -p 443:443 \
-v ./certs:/certs:ro \
-v ./config.json:/app/config/config.json:ro \
janmbaco/go-reverseproxy-ssl:v3
Alternative: Using environment variables with custom certificates:
docker run -d \
--name reverseproxy \
-p 80:80 -p 443:443 -p 8081:8081 \
-e DOMAIN=secure.internal.com \
-e BACKEND_HOST=backend \
-e BACKEND_PORT=8080 \
-e BACKEND_SCHEME=http \
-e CERT_FILE=/certs/internal.pem \
-e KEY_FILE=/certs/internal-key.pem \
-v ./certs:/certs:ro \
-v certs-storage:/app/certs \
janmbaco/go-reverseproxy-ssl:v3
Note: When using custom certificates with ENV vars, mount your certificate directory with
-vand specify paths withCERT_FILEandKEY_FILEenvironment variables.
Scenario: Route /api/* to API service, / to web
Limitation: This proxy routes by domain (not path). Use a single domain with backend path rewriting:
Workaround 1 - Use subdomains (recommended):
api.example.com → API servicewww.example.com → Web serviceWorkaround 2 - Backend handles routing:
Future: Path-based routing planned for v3.1
{
"web_virtual_hosts": [
{
"from": "example.com",
"scheme": "http",
"host_name": "localhost",
"port": 8080
}
],
"default_host": "example.com",
"reverse_proxy_port": ":443"
}
See docs/CONFIGURATION.md for complete reference including:
Note:
grpc_virtual_hosts,grpc_json_virtual_hosts, andssh_virtual_hostsare deprecated and ignored.
Point your domain to your server's public IP:
# A record
example.com A 203.0.113.10
api.example.com A 203.0.113.10
admin.example.com A 203.0.113.10
# Optional: IPv6
example.com AAAA 2001:db8::1
*.example.com A 203.0.113.10
Then any subdomain works: foo.example.com, bar.example.com, etc.
| Port | Protocol | Purpose |
|---|---|---|
| 80 | TCP | HTTP (redirects to HTTPS, Let's Encrypt challenges) |
| 443 | TCP | HTTPS (main traffic) |
| 8081 | TCP | Web Configuration UI (optional, can be localhost-only) |
Linux (UFW):
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
Linux (firewalld):
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
AWS Security Group:
HTTP TCP 80 0.0.0.0/0
HTTPS TCP 443 0.0.0.0/0
Docker Host:
# Ports automatically mapped with -p flag
docker run -p 80:80 -p 443:443 ...
https://example.com/app/certs/example.com/Requirements: DNS must point to your server, port 80 accessible from internet.
Yes! Set server_certificate in virtual host config:
{
"from": "example.com",
"server_certificate": {
"certificate_path": "/certs/example.pem",
"private_key_path": "/certs/example-key.pem"
}
}
Or set default certificate for all domains:
{
"default_server_cert": "/certs/default.pem",
"default_server_key": "/certs/default-key.pem"
}
Short answer: Not directly supported.
Alternatives:
app1.example.com, app2.example.comDocker Desktop (Mac/Windows):
host.docker.internal to access host machineDocker Linux:
172.17.0.1 (default bridge gateway)Docker Compose (recommended):
services:
proxy:
networks: [backend]
app:
networks: [backend]
Config:
{
"host_name": "app", // Service name, not localhost
"port": 3000
}
Docker logs:
docker logs -f reverseproxy
Log files (inside container):
/app/logs/YYYY-MM-DD.log
Log levels (in config.json):
{
"log_console_level": 4, // 1=Fatal, 2=Error, 3=Warning, 4=Info, 5=Trace
"log_file_level": 4
}
See docs/TROUBLESHOOTING.md for detailed troubleshooting, including:
Yes! Use grpc_web_virtual_hosts:
{
"grpc_web_virtual_hosts": [
{
"from": "grpcweb.example.com",
"scheme": "http",
"host_name": "grpc-backend",
"port": 9090
}
],
"default_host": "grpcweb.example.com",
"reverse_proxy_port": ":443"
}
Then use gRPC-Web client in JavaScript/TypeScript.
Quick start with ENV vars:
docker run -d \
--name reverseproxy \
-p 80:80 -p 443:443 -p 8081:8081 \
-e DOMAIN=example.com \
-e BACKEND_HOST=host.docker.internal \
-e BACKEND_PORT=3000 \
-v certs:/app/certs \
janmbaco/go-reverseproxy-ssl:v3
With custom config file:
docker run -d \
--name reverseproxy \
-p 80:80 -p 443:443 \
-v ./configs/config.json:/app/config/config.json:ro \
-v certs:/app/certs \
janmbaco/go-reverseproxy-ssl:v3
See docker-compose.quickstart.yml for complete example.
Requirements: Go 1.25+
git clone https://github.com/janmbaco/go-reverseproxy-ssl.git
cd go-reverseproxy-ssl
go build -o bin/reverseproxy ./cmd/reverseproxy
./bin/reverseproxy --config configs/config.json
go get github.com/janmbaco/go-reverseproxy-ssl/v3
package main
import "github.com/janmbaco/go-reverseproxy-ssl/v3/src/infrastructure"
func main() {
bootstrapper := infrastructure.NewServerBootstrapper("config.json")
bootstrapper.Start()
}
GNU General Public License v3.0 - see LICENSE file.
Key points:
Content type
Image
Digest
sha256:3fadc2281…
Size
14.4 MB
Last updated
11 months ago
docker pull janmbaco/go-reverseproxy-ssl