Network Access: Domain or IP
Nginx runs on the host and publishes the stack. Follow Option A if you chose the domain block in .env, or Option B if you chose the bare-IP block.
Nginx reads /etc/nginx/nginx.conf. The files in the repository's nginx/ folder are templates: editing them has no effect until they are copied to /etc/nginx/nginx.conf and Nginx is reloaded.
Install Nginx
sudo apt update
sudo apt install -y nginx
sudo systemctl status nginx
Option A: Domain with HTTPS
Step 1: Create the DNS Records
In the DNS provider that manages the customer's domain (Cloudflare, GoDaddy, Route53, etc.), create two A records:
| Type | Name | Value |
|---|---|---|
| A | onprem.customer-domain.com | SERVER_IP |
| A | default.customer-org-name.customer-domain.com | SERVER_IP |
The second name must match DOMAIN_URL in .env.
Step 2: Verify DNS Resolution
dig +short onprem.customer-domain.com @1.1.1.1
dig +short default.customer-org-name.customer-domain.com @1.1.1.1
Both must return the server's IP before you request certificates.
Step 3: Open the Firewall
sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable
sudo ufw status
Allow port 22 before enabling the firewall, or you will lock yourself out of SSH. Port 80 must be open for Certbot's domain validation.
Step 4: Obtain SSL Certificates
sudo apt install -y certbot python3-certbot-nginx
sudo certbot certonly --nginx -d onprem.customer-domain.com
sudo certbot certonly --nginx -d default.customer-org-name.customer-domain.com
A wildcard certificate for *.customer-domain.com does not cover the tenant name, because it is two labels deep - it needs its own certificate.
Step 5: Install the Nginx Configuration
The template uses example names. Copy it into place, then replace them with the customer's names:
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo cp nginx/nginx.conf /etc/nginx/nginx.conf
sudo rm -f /etc/nginx/sites-enabled/default
sudo sed -i 's/onprem\.prod\.authnull\.com/onprem.customer-domain.com/g; s/default\.beta\.prod\.authnull\.com/default.customer-org-name.customer-domain.com/g' /etc/nginx/nginx.conf
Then open /etc/nginx/nginx.conf and update the map $http_origin $cors_origin block at the top so that it allows the customer's two HTTPS origins.
The domain configuration refuses requests made to the bare IP address (return 444). Browse to the domain name.
Step 6: Test and Reload Nginx
sudo nginx -t && sudo systemctl reload nginx
Open https://onprem.customer-domain.com - the sign-in page should load.
Option B: Bare IP over HTTP
Use this when the server is reached by IP address only, for example on a private network over VPN. No DNS records or certificates are needed.
Step 1: Open the Firewall
sudo ufw allow 22
sudo ufw allow 80
sudo ufw enable
Step 2: Install the Nginx Configuration
nginx-ip.conf works for any IP address without editing - it allows any http://<ipv4> origin.
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo cp nginx/nginx-ip.conf /etc/nginx/nginx.conf
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
Ubuntu's Nginx package enables a default site that also listens on port 80 as the default server. The AuthNull configuration defines its own, and Nginx allows only one per port, so nginx -t fails with a "duplicate default server" error until that site is removed. sites-enabled/default is a link; the original stays in /etc/nginx/sites-available/.
Step 3: Verify
- Open
http://SERVER_IP/org/signup. The organization sign-up page should load - this confirms Nginx is serving the Admin UI. - Create the organization there, as described in Organization and Tenant Setup. The tenant only exists after this step.
- Open
http://SERVER_IP/tenant/login. You are redirected to the sign-in page, and its address should containdomainUrl=default.customer-org-name.customer-domain.com- the tenant fromDOMAIN_URL, not the IP address.
nginx-ip.conf includes a temporary patch (the location ~ ^/static/js/main... block) that makes the Admin UI send DOMAIN_URL instead of the browser's IP. Without it, the sign-in link carries domainUrl=SERVER_IP and the backend cannot find the organization. Leave it in place; it becomes a no-op once the Admin UI image includes the fix.
Next Steps
Continue to Organization and Tenant Setup to register your organization.