FreeBSD Standalone Deployment¶
Deploy R Commerce directly on FreeBSD without using jails. This is the simplest deployment method for single-server setups.
Supported FreeBSD Versions¶
- FreeBSD 14.2 - Latest production release (recommended)
- FreeBSD 15.0 - Current stable branch
When to Use Standalone Deployment¶
- Single application server - No need for isolation
- Development environment - Quick setup for testing
- Resource constraints - Avoid jail overhead
- Simple infrastructure - Easier management
Prerequisites¶
# FreeBSD 14.0 or later
freebsd-version
# Root or sudo access
# Internet connection for package installation
Installation¶
1. System Preparation¶
# Update system packages
pkg update
pkg upgrade -y
# Install required packages
pkg install -y \
postgresql15-server \
postgresql15-client \
redis \
nginx \
ca_root_nss \
curl \
sudo
# Enable services at boot
tee -a /etc/rc.conf << 'EOF'
postgresql_enable="YES"
redis_enable="YES"
nginx_enable="YES"
EOF
2. Database Setup¶
# Initialize PostgreSQL
service postgresql initdb
# Start PostgreSQL
service postgresql start
# Create database and user
su - postgres << 'EOF'
createdb rcommerce
createuser -P rcommerce
# Enter password when prompted
psql -c "GRANT ALL PRIVILEGES ON DATABASE rcommerce TO rcommerce;"
EOF
3. Redis Setup¶
4. Create R Commerce User¶
# Create dedicated user
pw useradd -n rcommerce -s /bin/sh -d /usr/local/rcommerce -m
# Add to sudoers for maintenance (optional)
echo "rcommerce ALL=(ALL) NOPASSWD: /usr/sbin/service rcommerce *" >> /usr/local/etc/sudoers.d/rcommerce
5. Install R Commerce¶
# Download latest release
curl -L -o /usr/local/bin/rcommerce \
"https://github.com/creativebastard/rcommerce/releases/latest/download/rcommerce-freebsd-amd64"
# Make executable
chmod +x /usr/local/bin/rcommerce
# Verify installation
rcommerce --version
6. Configuration¶
# Create configuration directory
mkdir -p /usr/local/etc/rcommerce
# Create configuration file
cat > /usr/local/etc/rcommerce/config.toml << 'EOF'
[server]
host = "127.0.0.1"
port = 8080
worker_threads = 4
[database]
db_type = "Postgres"
host = "localhost"
port = 5432
database = "rcommerce"
username = "rcommerce"
password = "your_secure_password"
pool_size = 20
[cache]
cache_type = "Redis"
redis_url = "redis://127.0.0.1:6379"
[logging]
level = "info"
format = "Json"
[media]
storage_type = "Local"
local_path = "/usr/local/rcommerce/uploads"
EOF
# Set permissions
chown -R rcommerce:rcommerce /usr/local/etc/rcommerce
chmod 600 /usr/local/etc/rcommerce/config.toml
# Create uploads directory
mkdir -p /usr/local/rcommerce/uploads
chown -R rcommerce:rcommerce /usr/local/rcommerce
7. rc.d Service Script¶
Create /usr/local/etc/rc.d/rcommerce:
#!/bin/sh
# PROVIDE: rcommerce
# REQUIRE: postgresql redis
# KEYWORD: shutdown
. /etc/rc.subr
name="rcommerce"
rcvar="rcommerce_enable"
load_rc_config $name
: ${rcommerce_enable:="NO"}
: ${rcommerce_config:="/usr/local/etc/rcommerce/config.toml"}
: ${rcommerce_user:="rcommerce"}
: ${rcommerce_group:="rcommerce"}
: ${rcommerce_dir:="/usr/local/rcommerce"}
command="/usr/local/bin/rcommerce"
procname="/usr/local/bin/rcommerce"
pidfile="/var/run/${name}.pid"
start_cmd="rcommerce_start"
stop_cmd="rcommerce_stop"
status_cmd="rcommerce_status"
reload_cmd="rcommerce_reload"
rcommerce_start() {
echo "Starting ${name}."
export RCOMMERCE_CONFIG=${rcommerce_config}
cd ${rcommerce_dir}
/usr/sbin/daemon -f -p ${pidfile} -u ${rcommerce_user} \
${command} server
}
rcommerce_stop() {
echo "Stopping ${name}."
if [ -f ${pidfile} ]; then
kill $(cat ${pidfile})
rm -f ${pidfile}
fi
}
rcommerce_status() {
if [ -f ${pidfile} ] && kill -0 $(cat ${pidfile}) 2>/dev/null; then
echo "${name} is running as pid $(cat ${pidfile})."
else
echo "${name} is not running."
return 1
fi
}
rcommerce_reload() {
echo "Reloading ${name} configuration..."
if [ -f ${pidfile} ]; then
kill -HUP $(cat ${pidfile})
else
echo "${name} is not running."
return 1
fi
}
run_rc_command "$1"
Enable the service:
8. Nginx Reverse Proxy¶
cat > /usr/local/etc/nginx/nginx.conf << 'EOF'
user www;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use kqueue;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
upstream rcommerce {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name _;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Health check endpoint (no rate limit)
location /health {
proxy_pass http://rcommerce;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# API endpoints with rate limiting
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://rcommerce;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# Static files
location /uploads/ {
alias /usr/local/rcommerce/uploads/;
expires 1y;
add_header Cache-Control "public, immutable";
}
# Default location
location / {
proxy_pass http://rcommerce;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
EOF
# Test nginx configuration
nginx -t
# Start nginx
service nginx start
9. Start R Commerce¶
# Start the service
service rcommerce start
# Check status
service rcommerce status
# View logs
tail -f /var/log/rcommerce.log
SSL/TLS with Let's Encrypt¶
# Install certbot
pkg install py39-certbot
# Obtain certificate
certbot certonly --standalone -d yourdomain.com
# Update nginx configuration for SSL
# (See reverse proxy documentation for full SSL config)
Monitoring¶
# Install monitoring tools
pkg install monit
# Create monit configuration
cat > /usr/local/etc/monit.d/rcommerce << 'EOF'
check process rcommerce matching "/usr/local/bin/rcommerce"
start program = "/usr/sbin/service rcommerce start"
stop program = "/usr/sbin/service rcommerce stop"
if failed host 127.0.0.1 port 8080 protocol http
request /health
with timeout 10 seconds
then restart
if 5 restarts within 5 cycles then timeout
EOF
sysrc monit_enable=YES
service monit start
Backup Strategy¶
# Database backup
pg_dump -U rcommerce rcommerce > /backup/rcommerce-$(date +%Y%m%d).sql
# File backup
tar -czf /backup/rcommerce-files-$(date +%Y%m%d).tar.gz /usr/local/rcommerce/uploads
# Automated backup script
cat > /usr/local/bin/backup-rcommerce.sh << 'EOF'
#!/bin/sh
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d)
# Database
pg_dump -U rcommerce rcommerce | gzip > $BACKUP_DIR/rcommerce-db-$DATE.sql.gz
# Files
tar -czf $BACKUP_DIR/rcommerce-files-$DATE.tar.gz /usr/local/rcommerce/uploads
# Keep only last 7 days
find $BACKUP_DIR -name "rcommerce-*" -mtime +7 -delete
EOF
chmod +x /usr/local/bin/backup-rcommerce.sh
# Add to cron
0 2 * * * /usr/local/bin/backup-rcommerce.sh
Troubleshooting¶
| Issue | Solution |
|---|---|
| Service won't start | Check service rcommerce status and logs |
| Database connection failed | Verify PostgreSQL is running and credentials |
| Port already in use | Check with sockstat -4 -l |
| Permission denied | Check file ownership with ls -la |
| Out of memory | Check with top or vmstat |
See Also¶
- Jail Deployment - Deploy with iocage jails
- rc.d Service - Service management details
- Nginx Reverse Proxy
- Operations Overview