ODK Central with nonstandard port number and custom SSL: Cannot retrieve forms with Collect

After a bit of experimenting, I've successfully managed to get it to work. Thanks to @yanokwa for pointing me in the right direction.

What I actually end up with:
One machine, one IP address, two services:

  • an Apache server that was already running on the machine and could not be altered
  • ODK represented by an nginx server in Docker
    A reverse proxy server was needed to separate requests for Apache and ODK. The separation is ensured by setting ODK to listen to custom ports. Apache keeps listening to standard ports :80 and :443.

Assumptions:

  • ODK was already installed, configured to listen to custom ports :4480 and :4443. This configuration does not work perfectly, which is why we're here. It's probably better if you apply these steps appropriately during installation.
  • The current domain my.example.com already has a Let's Encrypt certificate.
  • Root access.

There were three necessary things to do:

  1. Register a new subdomain: survey.example.com
  2. Set up a reverse proxy
  3. Rebuild nginx

Disclaimer: the order of these steps is what it probably should be, but I didn't try it this way. Due to the experimenting involved the actual order of successful steps is shrouded in mystery.

Setting a new subdomain

Add a new DNS record. Then add the new subdomain to your Let's Encrypt certificate:

sudo certbot --expand -d my.example.com -d survey.example.com

The reverse proxy

Add the following content to httpd.conf. The three marked lines were probably added by certbot. I'm pretty sure I didn't put them there. (I ran certbot after modifying httpd.conf.) If certbot does not add those three lines, add them manually. Be sure the addresses are correct and the files exist.

<VirtualHost *:80>
    ServerName survey.example.com
    ProxyPreserveHost On
    ProxyPass / http://localhost:4480/           # 4480 is the alternative for port 80
    ProxyPassReverse / http://localhost:4480/
</VirtualHost>

<VirtualHost _default_:443>
    SSLProxyEngine On
    ServerName survey.example.com
    ProxyPreserveHost On
    ProxyPass / https://localhost:4443/          # 4443 is an alternative for 443
    ProxyPassReverse / https://localhost:4443/
    
    SSLCertificateFile /etc/letsencrypt/live/my.example.com/fullchain.pem   # added by certbot
    SSLCertificateKeyFile /etc/letsencrypt/live/my.example.com/privkey.pem  # added by certbot
    Include /etc/letsencrypt/options-ssl-apache.conf                        # added by certbot
</VirtualHost>

After saving the config file don't forget to reload it.
sudo apachectl -k graceful

Rebuild nginx

.env is now this:

SSL_TYPE=letsencrypt
DOMAIN=survey.example.com
SYSADMIN_EMAIL=my.mail@example.com

I didn't have to change docker-compose.yml but I'm adding it here to be complete.
This just the nginx chapter, and only the two commented lines are going to be changed.

nginx:
    container_name: nginx
    build:
      context: .
      dockerfile: nginx.dockerfile
    depends_on:
      - service
    environment:
      - SSL_TYPE=${SSL_TYPE}
      - DOMAIN=${DOMAIN}
      - CERTBOT_EMAIL=${SYSADMIN_EMAIL}
    ports:
      - "4480:80"   # on the left goes the alternative port number, on right the real port 
      - "4443:443"  # and the same applies for https  
    healthcheck:
      test: [ "CMD-SHELL", "nc -z localhost 443 || exit 1" ]

Then run docker-compose build in your working folder and run the usual steps:
docker-compose up --no-start
sudo systemctl start docker-compose@central
Check systemctl status docker-compose@central and docker ps -a. Everything green, up and healthy? Good. Now it should work. If not, try the steps in a different order.

4 Likes