Table of Contents [hide]
Recently I developed an API with Spring Boot. All the tests on the local environment went well with Postman. However, when deploying to prod through HAProxy, I got this CORS error:

There are also other errors regarding missing headers, origin…
There are some solutions available, such as adding code to my Spring Boot code base. I don’t like this method since it’s not pure
.
Why add non-business code in API?
That’s why I need to find another solution.
It turned out, that the solution is simple.
If you prefer to watch the video, here it is:
Enable CORS for OPTIONS request in HAProxy
First, add a new backend only for serving CORS in HAProxy:
backend cors_backend
http-after-response set-header Access-Control-Allow-Origin "*"
http-after-response set-header Access-Control-Allow-Headers "*"
http-after-response set-header Access-Control-Max-Age "31536000"
http-request return status 200
Now, in the frontend part, add a check for OPTIONS
request and direct that request to this backend:
frontend your_fe
...
acl is_options method OPTIONS
...
use_backend cors_backend if is_options
# put your actual backend below this
Of course, in your actual backend, you need to set the CORS headers:
backend your_main_backend
...
# START CORS
http-response add-header Access-Control-Allow-Origin "*"
http-response add-header Access-Control-Allow-Headers "*"
http-response add-header Access-Control-Max-Age 3600
http-response add-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH"
# END CORS
server w1 server:8080
And that’s all you need. Now you can work with your API CORS-free
The Complete configuration
Here are the complete configuration files:
- docker-compose.yml
version'3.8'
services
haproxy_license_server
container_name haproxy_license_server
image haproxy2.4.0
restart always
ports
"7088:7088"
"8789:8788"
volumes
./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- haproxy.cfg
global
stats timeout 30s
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
option forwardfor
option http-server-close
frontend ukata
bind :8788
mode tcp
acl is_options method OPTIONS
use_backend cors_backend if is_options
default_backend ukata_backend
backend cors_backend
http-after-response set-header Access-Control-Allow-Origin "*"
http-after-response set-header Access-Control-Allow-Headers "*"
http-after-response set-header Access-Control-Allow-Credentials "true"
http-after-response set-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH"
http-after-response set-header Access-Control-Max-Age "31536000"
http-request return status 200
backend ukata_backend
mode http
balance roundrobin
# START CORS
http-response add-header Access-Control-Allow-Origin "http://localhost:4200"
http-response add-header Access-Control-Allow-Headers "*"
http-response add-header Access-Control-Max-Age 3600
http-after-response set-header Access-Control-Allow-Credentials "true"
http-response add-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH"
# END CORS
# Don't set IP address of the server, use the hostname instead
# set local-dev-1, 2 to your local ip address (192.168.x.x)
server w1 192.168.100.6:8788 check
Caution
On a production server, you may need to replace the “*” with only the hosts you allowed (from your frontend, for example). In that case, you can replace * with your client URL (starts with http/https).

I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.
Hey, Thanks for this article, I am currently stuck with this problem, But I was unable to solve this:
I have a single frontend application with multiple backend, Can you publish your ha-proxy config file and replace the confidential data with a dump one, May be via Github , Thanks
CORS is conceived to protect your site from XSS attacks. That way you are completely giving up on this protection.
Agree. However, this is for development only. For production, you need to actually specify the allowed origin.
http-after-response doesn’t exists in HAPROXY configration