summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-20 16:56:46 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-20 16:56:46 -1000
commit5b6defbc8c3082013a86b727b4c75370ba3385c7 (patch)
tree01e3d21c6d83abcdfa46488ecea35e542a1d9cc1 /docs
parent845dda44574fb69cf7af3c2b4df9021451db8b11 (diff)
Update deployment docs with real-world fixes
- Add explicit permission steps (755 dirs, 644 files) - Document systemd override for .env sourcing - Expand troubleshooting with common errors: - AH01144 proxy module error - 403 forbidden on static files - Template nil pointer panic - Readonly database error Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/deployment.md185
1 files changed, 133 insertions, 52 deletions
diff --git a/docs/deployment.md b/docs/deployment.md
index 89d2bc6..5845948 100644
--- a/docs/deployment.md
+++ b/docs/deployment.md
@@ -18,8 +18,14 @@ Deploy Task Dashboard to a VPS using Apache2 as reverse proxy and Systemd for pr
│ └── dashboard.db # SQLite database
├── public/ # Static assets (served by Apache)
│ ├── css/
+│ │ └── output.css
│ └── js/
+│ ├── htmx.min.js
+│ └── app.js
├── templates/ # HTML templates
+│ ├── index.html
+│ ├── login.html
+│ └── partials/
└── .env # Environment configuration
```
@@ -38,27 +44,41 @@ GOOS=linux GOARCH=amd64 go build -o app cmd/dashboard/main.go
```bash
export FQDN="your-domain.com"
-sudo mkdir -p /site/${FQDN}/{data,public,templates}
-sudo chown -R www-data:www-data /site/${FQDN}
+mkdir -p /site/${FQDN}/{data,public/css,public/js,templates/partials}
```
### 2. Deploy Files
```bash
# Copy binary
-sudo cp app /site/${FQDN}/
+cp app /site/${FQDN}/
# Copy static assets
-sudo cp -r web/static/* /site/${FQDN}/public/
+cp -r web/static/* /site/${FQDN}/public/
-# Copy templates
-sudo cp -r web/templates/* /site/${FQDN}/templates/
+# Copy templates (including partials)
+cp -r web/templates/* /site/${FQDN}/templates/
+```
+
+### 3. Set Permissions
+
+**Important:** The app runs as `www-data`. All directories need 755, all files need 644.
+
+```bash
+# Set ownership
+chown -R www-data:www-data /site/${FQDN}
-# Set permissions
-sudo chmod +x /site/${FQDN}/app
+# Set directory permissions (755 = rwxr-xr-x)
+find /site/${FQDN} -type d -exec chmod 755 {} \;
+
+# Set file permissions (644 = rw-r--r--)
+find /site/${FQDN} -type f -exec chmod 644 {} \;
+
+# Make binary executable
+chmod +x /site/${FQDN}/app
```
-### 3. Configure Environment
+### 4. Configure Environment
Create `/site/${FQDN}/.env`:
@@ -71,10 +91,10 @@ TRELLO_TOKEN=your_trello_token
# Optional
PLANTOEAT_API_KEY=your_plantoeat_api_key
-# Paths (adjust for deployment structure)
-DATABASE_PATH=/site/${FQDN}/data/dashboard.db
-TEMPLATE_DIR=/site/${FQDN}/templates
-STATIC_DIR=/site/${FQDN}/public
+# Paths (use absolute paths)
+DATABASE_PATH=/site/your-domain.com/data/dashboard.db
+TEMPLATE_DIR=/site/your-domain.com/templates
+STATIC_DIR=/site/your-domain.com/public
# Server
PORT=8080
@@ -89,89 +109,150 @@ DEFAULT_PASS=your_secure_password
Secure the file:
```bash
-sudo chmod 600 /site/${FQDN}/.env
-sudo chown www-data:www-data /site/${FQDN}/.env
+chmod 600 /site/${FQDN}/.env
+chown www-data:www-data /site/${FQDN}/.env
+```
+
+### 5. Install Systemd Service
+
+Copy the service file:
+
+```bash
+cp deployment/task-dashboard.service /etc/systemd/system/task-dashboard@.service
```
-### 4. Install Systemd Service
+The default service uses `EnvironmentFile`, but godotenv expects to load `.env` from the working directory. Create an override to source it properly:
```bash
-# Copy and customize service file
-sudo cp deployment/task-dashboard.service /etc/systemd/system/task-dashboard@.service
+systemctl edit task-dashboard@${FQDN}
+```
+
+Add:
+
+```ini
+[Service]
+ExecStart=
+ExecStart=/bin/bash -c 'cd /site/%i && source .env && ./app'
+```
+
+Enable and start:
-# Enable and start service
-sudo systemctl daemon-reload
-sudo systemctl enable task-dashboard@${FQDN}
-sudo systemctl start task-dashboard@${FQDN}
+```bash
+systemctl daemon-reload
+systemctl enable task-dashboard@${FQDN}
+systemctl start task-dashboard@${FQDN}
# Check status
-sudo systemctl status task-dashboard@${FQDN}
+systemctl status task-dashboard@${FQDN}
```
-### 5. Configure Apache
+### 6. Configure Apache
+
+Enable required modules:
```bash
-# Enable required modules
-sudo a2enmod proxy proxy_http ssl headers rewrite
+a2enmod proxy proxy_http ssl headers rewrite
+```
-# Copy and customize Apache config
-# Replace ${FQDN} with your actual domain in the config file
-sudo cp deployment/apache.conf /etc/apache2/sites-available/${FQDN}.conf
+Copy and customize Apache config:
-# Edit the file to replace ${FQDN} placeholders
-sudo sed -i "s/\${FQDN}/${FQDN}/g" /etc/apache2/sites-available/${FQDN}.conf
+```bash
+cp deployment/apache.conf /etc/apache2/sites-available/${FQDN}.conf
+
+# Replace ${FQDN} placeholders with your actual domain
+sed -i "s/\${FQDN}/${FQDN}/g" /etc/apache2/sites-available/${FQDN}.conf
# Enable site
-sudo a2ensite ${FQDN}
+a2ensite ${FQDN}
# Test and reload
-sudo apache2ctl configtest
-sudo systemctl reload apache2
+apache2ctl configtest
+systemctl reload apache2
```
-### 6. SSL Certificate (Let's Encrypt)
+### 7. SSL Certificate (Let's Encrypt)
```bash
-sudo apt install certbot python3-certbot-apache
-sudo certbot --apache -d ${FQDN}
+apt install certbot python3-certbot-apache
+certbot --apache -d ${FQDN}
```
## Verification
-1. Check service is running: `sudo systemctl status task-dashboard@${FQDN}`
-2. Check logs: `sudo journalctl -u task-dashboard@${FQDN} -f`
+1. Check service is running: `systemctl status task-dashboard@${FQDN}`
+2. Check logs: `journalctl -u task-dashboard@${FQDN} -f`
3. Visit `https://${FQDN}` and login with configured credentials
+4. Change the default password after first login
## Updating
```bash
# Stop service
-sudo systemctl stop task-dashboard@${FQDN}
+systemctl stop task-dashboard@${FQDN}
# Deploy new binary
-sudo cp app /site/${FQDN}/
+cp app /site/${FQDN}/
# Update static assets if changed
-sudo cp -r web/static/* /site/${FQDN}/public/
+cp -r web/static/* /site/${FQDN}/public/
# Update templates if changed
-sudo cp -r web/templates/* /site/${FQDN}/templates/
+cp -r web/templates/* /site/${FQDN}/templates/
+
+# Fix permissions
+chown -R www-data:www-data /site/${FQDN}
+find /site/${FQDN} -type d -exec chmod 755 {} \;
+find /site/${FQDN} -type f -exec chmod 644 {} \;
+chmod +x /site/${FQDN}/app
+chmod 600 /site/${FQDN}/.env
# Start service
-sudo systemctl start task-dashboard@${FQDN}
+systemctl start task-dashboard@${FQDN}
```
## Troubleshooting
### Service won't start
-- Check logs: `sudo journalctl -u task-dashboard@${FQDN} -e`
-- Verify .env file exists and has correct permissions
-- Ensure database directory is writable
+
+Check logs:
+```bash
+journalctl -u task-dashboard@${FQDN} -e
+```
+
+Common issues:
+- **"TODOIST_API_KEY is required"**: The .env file isn't being loaded. Use the systemctl override to source it (see step 5).
+- **"readonly database"**: The `data/` directory isn't writable by www-data. Run `chown www-data:www-data /site/${FQDN}/data`.
+- **Template panic/nil pointer**: Template files have wrong permissions. Run `chmod 644` on all `.html` files.
### 502 Bad Gateway
-- Check if Go app is running: `sudo systemctl status task-dashboard@${FQDN}`
-- Verify PORT in .env matches Apache ProxyPass
-### Static files not loading
-- Ensure `/site/${FQDN}/public/` contains CSS/JS files
-- Check Apache logs: `sudo tail -f /var/log/apache2/${FQDN}-error.log`
+- Check if Go app is running: `systemctl status task-dashboard@${FQDN}`
+- Verify PORT in .env matches Apache ProxyPass (default: 8080)
+
+### AH01144: No protocol handler was valid
+
+Apache proxy modules aren't loaded:
+```bash
+a2enmod proxy proxy_http
+systemctl restart apache2
+```
+
+### 403 Forbidden on static files
+
+Permission issue. Fix:
+```bash
+chmod -R 755 /site/${FQDN}/public
+find /site/${FQDN}/public -type f -exec chmod 644 {} \;
+chown -R www-data:www-data /site/${FQDN}/public
+```
+
+### 404 on static files
+
+Static files not copied. Ensure the structure exists:
+```bash
+ls -la /site/${FQDN}/public/css/output.css
+ls -la /site/${FQDN}/public/js/htmx.min.js
+ls -la /site/${FQDN}/public/js/app.js
+```
+
+If missing, copy from `web/static/`.