# Setting up a secure reverse-proxy for Belenios

We give here instructions for setting up a secure reverse-proxy with
nginx and Let's Encrypt on a Debian 12 system. We assume the public
address will be https://vote.example.org; please adapt as needed.

## Basic setup of nginx + Let's Encrypt

As root:
```
apt install nginx-light nginx libnginx-mod-http-headers-more-filter certbot python3-certbot-nginx
cat > /etc/nginx/sites-available/vote.example.org <<EOF
server {
    server_name vote.example.org;
    root /var/www/html;
    listen 80;
    listen [::]:80;
}
EOF
cd /etc/nginx/sites-enabled
ln -s ../sites-available/vote.example.org .
systemctl restart nginx.service
certbot --nginx
```

## Configuring the reverse-proxy for Belenios

Add (and adapt) the following section to the relevant section of
`/etc/nginx/sites-available/vote.example.org`:
```
    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
```

Run `systemctl restart nginx.service` (as root).

## Configuring Belenios for being behind a reverse-proxy

We suppose Belenios has been compiled and deployed using instructions
[here](../contrib/nspawn/README.md). The following are hints to be
applied to the `ocsigenserver.conf.in` file.

Make sure Belenios listens on `127.0.0.1` only:
```
    <port>127.0.0.1:8001</port>
```

Make Belenios aware of its public address:
```
    <host charset="utf-8" hostfilter="*" defaulthostname="vote.example.org">
      ...
      <eliom name="belenios">
        <public-url prefix="https://vote.example.org"/>
        ...
      </eliom>
    </host>
```

Make sure you restart Belenios after applying your changes:
```
systemctl restart belenios-container@main.service
```

## Hardening the reverse-proxy

Add the following lines to the relevant section of
`/etc/nginx/sites-available/vote.example.org`:
```
    more_clear_headers Server;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'; img-src 'self' data:;" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer" always;
    proxy_cookie_flags ~ secure httponly samesite=strict;
```

Note that `samesite=strict` is incompatible with external voter
authentication. If you intend to authenticate voters with CAS or
OpenID Connect, you may use `samesite=none` instead.

Run `systemctl restart nginx.service` (as root).

## Checking that everything works

Go to https://vote.example.org and perform any tests you wish. In
particular, check that URLs generated by the system in sent e-mails
are correct.
