Production Deployment#
This guide covers deploying NexusLIMS-CDCS to a production environment with proper security, SSL certificates, and data management.
Prerequisites#
Required Knowledge#
Linux system administration
Docker and Docker Compose
Basic understanding of DNS and SSL/TLS certificates
Basic PostgreSQL database administration
Web server/reverse proxy concepts
Required Access#
Root or sudo access to production server
DNS management for your domain
(Optional) CIFS/SMB or NFS for data files
(Optional) SMTP server for application notifications
System Requirements#
Minimum Hardware#
Resource |
Minimum |
Recommended |
|---|---|---|
CPU |
4 cores |
8 cores |
RAM |
8 GB |
16 GB |
Disk |
20 GB SSD |
100+ GB SSD |
Network |
100 Mbps |
1 Gbps |
Software Requirements#
Software |
Version |
|---|---|
OS |
Ubuntu 22.04 LTS or RHEL 8+ |
Docker |
24.0+ |
Docker Compose |
2.20+ |
Git |
2.0+ |
Network Requirements#
Firewall: Ports 80 and 443 open (for ACME certificate validation)
DNS: Ability to create A records pointing to your server
Optional: Firewall rules for database ports if external access needed
Pre-Deployment Checklist#
Before deploying, ensure you have:
Production server provisioned and accessible via SSH
Domain name(s) registered and DNS configured
SSL certificate strategy determined (either self-managed certs or automatic ACME/Let’s Encrypt)
Data storage locations identified and accessible
Backup strategy planned
Strong passwords generated for database and Redis
Django secret key generated (minimum 50 characters)
(Optional) SMTP server configured for email notifications
Domain and DNS Setup#
Required DNS Records#
You need two subdomains (replace nexuslims.example.com with your domain):
Main application:
nexuslims.example.comFile server:
files.nexuslims.example.com
DNS Configuration#
Create A records pointing to your server’s public IP:
nexuslims.example.com. A 203.0.113.42
files.nexuslims.example.com. A 203.0.113.42
Verify DNS Propagation#
Before deployment, verify DNS is working:
dig nexuslims.example.com
dig files.nexuslims.example.com
Both should return your server’s IP address.
SSL Certificate Options#
Option 1: Automatic ACME (Recommended)#
Best for: Production deployments with public network access
Caddy automatically obtains and renews certificates from Let’s Encrypt:
Set
CADDY_ACME_EMAILin your.envfileEnsure ports 80 and 443 are accessible from the internet
Caddy handles everything else automatically
Advantages:
Fully automated certificate issuance and renewal
Free certificates from Let’s Encrypt
Trusted by all browsers
No manual intervention required
Option 2: Manual Certificates#
Best for: Organizations with existing PKI or certificate vendors
Obtain certificates from your CA (you need
fullchain.pemandprivkey.pem)Create certificate directory and copy certificates:
mkdir -p /opt/nexuslims/certs chmod 700 /opt/nexuslims/certs cp fullchain.pem /opt/nexuslims/certs/ cp privkey.pem /opt/nexuslims/certs/ chmod 600 /opt/nexuslims/certs/*
Set the certificate path in your
.envfile:CADDY_CERTS_HOST_PATH=/opt/nexuslims/certs
The
docker-compose.prod.ymlalready includes a volume mount that uses this variable:- ${CADDY_CERTS_HOST_PATH}:/etc/caddy/certs:ro
Update
caddy/Caddyfile.prodto use the certificates:https://{$DOMAIN} { tls /etc/caddy/certs/fullchain.pem /etc/caddy/certs/privkey.pem # ... rest of config } https://{$FILES_DOMAIN} { tls /etc/caddy/certs/fullchain.pem /etc/caddy/certs/privkey.pem # ... rest of config }
Note
When using manual certificates, you are responsible for renewing them before expiration.
Environment Configuration#
1. Clone Repository#
sudo mkdir -p /opt/nexuslims
cd /opt/nexuslims
git clone https://github.com/datasophos/NexusLIMS-CDCS.git
cd NexusLIMS-CDCS/deployment
2. Create Environment File#
cp .env.prod.example .env
chmod 600 .env
3. Configure Environment Variables#
Edit .env with your production values. See Configuration for detailed documentation of all variables.
Critical variables to set:
# Domain configuration
DOMAIN=nexuslims.example.com
FILES_DOMAIN=files.nexuslims.example.com
# Security (generate strong values!)
SECRET_KEY=your-50-character-minimum-secret-key
POSTGRES_PASS=strong-database-password
REDIS_PASS=strong-redis-password
# ACME certificate email
CADDY_ACME_EMAIL=admin@example.com
# File paths (adjust to your storage locations)
NX_DATA_HOST_PATH=/mnt/nexuslims/data
NX_INSTRUMENT_DATA_HOST_PATH=/mnt/nexuslims/instrument-data
NX_CDCS_BACKUPS_HOST_PATH=/opt/nexuslims/backups
Warning
Never commit .env to version control! It contains secrets.
File Storage Setup#
NexusLIMS-CDCS serves two types of files:
NexusLIMS data: Thumbnail images, metadata files
Instrument data: Raw microscopy data files
Option 1: Local Storage#
sudo mkdir -p /mnt/nexuslims/data
sudo mkdir -p /mnt/nexuslims/instrument-data
sudo chown -R $USER:$USER /mnt/nexuslims
sudo chmod -R 755 /mnt/nexuslims
Option 2: NFS Mount#
# Install NFS client
sudo apt-get install nfs-common # Ubuntu/Debian
# Create mount points
sudo mkdir -p /mnt/nexuslims/data
sudo mkdir -p /mnt/nexuslims/instrument-data
# Mount NFS shares
sudo mount -t nfs nfs-server:/export/nexuslims/data /mnt/nexuslims/data
sudo mount -t nfs nfs-server:/export/nexuslims/instrument-data /mnt/nexuslims/instrument-data
# Add to /etc/fstab for persistence
echo "nfs-server:/export/nexuslims/data /mnt/nexuslims/data nfs defaults 0 0" | sudo tee -a /etc/fstab
echo "nfs-server:/export/nexuslims/instrument-data /mnt/nexuslims/instrument-data nfs defaults 0 0" | sudo tee -a /etc/fstab
Option 3: CIFS/SMB Mount#
# Install CIFS utilities
sudo apt-get install cifs-utils # Ubuntu/Debian
# Create credentials file
sudo mkdir -p /etc/smbcredentials
sudo touch /etc/smbcredentials/nexuslims.cred
sudo chmod 600 /etc/smbcredentials/nexuslims.cred
sudo tee /etc/smbcredentials/nexuslims.cred > /dev/null << EOF
username=your_smb_username
password=your_smb_password
domain=WORKGROUP
EOF
# Create mount points and mount
sudo mkdir -p /mnt/nexuslims/data
sudo mkdir -p /mnt/nexuslims/instrument-data
sudo mount -t cifs //nas-server/nexuslims-data /mnt/nexuslims/data \
-o credentials=/etc/smbcredentials/nexuslims.cred,uid=$(id -u),gid=$(id -g)
sudo mount -t cifs //nas-server/nexuslims-instrument-data /mnt/nexuslims/instrument-data \
-o credentials=/etc/smbcredentials/nexuslims.cred,uid=$(id -u),gid=$(id -g)
Deployment#
1. Load Admin Commands#
cd /opt/nexuslims/NexusLIMS-CDCS/deployment
source admin-commands.sh
This provides the dc-prod alias (shortcut for docker compose -f docker-compose.base.yml -f docker-compose.prod.yml).
2. Build and Pull Images#
dc-prod build # Build CDCS and Caddy images
dc-prod pull # Pull PostgreSQL and Redis images
3. Start Services#
dc-prod up -d
4. Monitor Startup#
# Watch logs
dc-prod logs -f
# Check service status
dc-prod ps
All services should show Up and healthy.
5. Verify Certificate Acquisition#
If using ACME, watch Caddy logs for certificate issuance:
dc-prod logs -f caddy
You should see: certificate obtained successfully
Post-Deployment Setup#
1. Run Initialization Script#
The initialization script sets up the superuser, schema, and XSLT stylesheets:
admin-init
This will:
Verify database migrations are complete
Create superuser (prompts for credentials)
Upload NexusLIMS schema
Load and configure XSLT stylesheets
Load data exporters
2. Verify Installation#
admin-stats
Expected output:
============================================================
NexusLIMS-CDCS System Statistics
============================================================
Users:
Total: 1
Superusers: 1
Templates:
Total: 1
- Nexus Experiment Schema (Version 1)
XSLT Stylesheets:
Total: 2
- detail_stylesheet.xsl
- list_stylesheet.xsl
============================================================
3. Test File Serving#
Navigate to:
https://files.nexuslims.example.com/data/https://files.nexuslims.example.com/instrument-data/
Both should show directory listings.
4. Create Backup Directory#
sudo mkdir -p /opt/nexuslims/backups
sudo chown $USER:$USER /opt/nexuslims/backups
Important
The backup directory must be owned by the user running Docker, not root. Otherwise backup scripts will fail with permission errors.
Restart services to pick up the mount:
dc-prod down
dc-prod up -d
5. Configure Automated Backups#
Create a daily backup script:
cat > /opt/nexuslims-backup.sh << 'EOF'
#!/bin/bash
set -e
cd /opt/nexuslims/NexusLIMS-CDCS/deployment
source admin-commands.sh
# Run backup
admin-backup
# Also create a database dump
admin-db-dump
# Remove backups older than 30 days
find /opt/nexuslims/backups -type d -name "backup_*" -mtime +30 -exec rm -rf {} \; 2>/dev/null || true
find /opt/nexuslims/backups -type f -name "backup_*.sql" -mtime +30 -delete 2>/dev/null || true
EOF
chmod +x /opt/nexuslims-backup.sh
# Add to crontab (daily at 2 AM)
(crontab -l 2>/dev/null; echo "0 2 * * * /opt/nexuslims-backup.sh") | crontab -
Security Hardening#
Firewall Configuration#
UFW (Ubuntu):
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP (for ACME)
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
firewalld (RHEL):
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
Database Security#
Don’t expose PostgreSQL port externally unless necessary
Use strong passwords (already set in
.env)Keep PostgreSQL container updated
Container Security#
Keep images updated regularly:
dc-prod pull
dc-prod up -d
Log Rotation#
Configure Docker log rotation in /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Restart Docker: sudo systemctl restart docker
Upgrading#
Application Updates#
Backup current deployment:
source admin-commands.sh admin-backup
Pull latest code:
cd /opt/nexuslims/NexusLIMS-CDCS git fetch git checkout v3.19.0 # or desired version
Review changelog for breaking changes
Check for new environment variables in
.env.prod.exampleRebuild and restart:
cd deployment source admin-commands.sh dc-prod build dc-prod down dc-prod up -d
Run migrations:
docker exec nexuslims_prod_cdcs python manage.py migrate
Rollback#
If upgrade fails:
dc-prod down
git checkout v3.18.0 # Previous version
cd deployment
dc-prod build
dc-prod up -d
If database schema changed, restore from backup:
admin-db-restore /opt/nexuslims/backups/backup_20260109_120000.sql
Next Steps#
Configuration - Detailed environment variable reference
Administration - Backup, restore, and maintenance procedures
Troubleshooting - Common issues and solutions
Local Test Deployment - Test production config locally with mkcert