| Service | File | Purpose | Auto-start |
|---|---|---|---|
| gunicorn | /etc/systemd/system/gunicorn.service | Django web server | ✅ |
| celery | /etc/systemd/system/celery.service | Background task worker | ✅ |
| celerybeat | /etc/systemd/system/celerybeat.service | Scheduled task runner | ✅ |
| nginx | (package default) | Web server / reverse proxy | ✅ |
| postgresql | (package default) | Database | ✅ |
| redis-server | (package default) | Cache / message broker | ✅ |
| docker | (package default) | Container runtime (Wiki.js) | ✅ |
Runs the Django application. Listens on a Unix socket at /var/www/yealinbilling/gunicorn.sock. Nginx forwards all /api/ and /admin/ requests to this socket. Runs 3 worker processes.
Executes background tasks — things that would be too slow to do during a web request:
The scheduler — triggers tasks on a schedule stored in the database. Current scheduled tasks:
core.refresh_fx_rate — runs every hour, fetches live USD/AUD rateReverse proxy that routes:
/api/* → Gunicorn/admin/* → Gunicorn/static/* → staticfiles directory/media/* → media directoryThe database. All application data lives here. Never directly edit the database unless you know what you're doing — use Django admin or the API.
Used as the message broker between Django and Celery. When a task is triggered (e.g. billing run), it's put on the Redis queue and Celery picks it up.
# Start a service
sudo systemctl start gunicorn
# Stop a service
sudo systemctl stop gunicorn
# Restart a service
sudo systemctl restart gunicorn
# Check service status
sudo systemctl status gunicorn --no-pager
# View service logs
sudo journalctl -u gunicorn -n 100 --no-pager
# Follow service logs in real time
sudo journalctl -u gunicorn -f
# Enable service to start on reboot
sudo systemctl enable gunicorn
# Disable service from starting on reboot
sudo systemctl disable gunicorn
# Reload systemd after editing a service file
sudo systemctl daemon-reload
Location: /etc/systemd/system/gunicorn.service
[Unit]
Description=Yealin Billing — Gunicorn Django App Server
After=network.target postgresql.service redis.service
[Service]
User=crip
Group=www-data
WorkingDirectory=/var/www/yealinbilling
Environment="DJANGO_SETTINGS_MODULE=config.settings.production"
EnvironmentFile=/var/www/yealinbilling/.env
ExecStart=/var/www/yealinbilling/venv/bin/gunicorn --workers 3 --bind unix:/var/www/yealinbilling/gunicorn.sock --umask 007 --access-logfile /var/www/yealinbilling/logs/gunicorn-access.log --error-logfile /var/www/yealinbilling/logs/gunicorn-error.log --log-level info --timeout 120 config.wsgi:application
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Key settings:
--workers 3 — 3 parallel worker processes. Increase to 5 for more load.--umask 007 — socket permissions so Nginx (www-data) can connect--timeout 120 — kills workers that take longer than 120 secondsWiki.js runs in Docker containers, not systemd. Docker itself is managed by systemd and auto-starts on reboot. The containers are configured with restart: unless-stopped so they start automatically when Docker starts.
# Check Wiki.js containers
cd /opt/wikijs
docker compose ps
# View Wiki.js logs
docker compose logs -f wikijs
# Restart Wiki.js
docker compose restart wikijs
# Stop Wiki.js
docker compose down
# Start Wiki.js
docker compose up -d
# Update Wiki.js to latest version
docker compose pull
docker compose up -d