From cbae1d1a95df713eede0f0bd782d42dedda9b421 Mon Sep 17 00:00:00 2001 From: enki Date: Sun, 11 May 2025 19:23:56 -0700 Subject: [PATCH] Readme update and fixed Nginx CORS issues --- README.md | 114 ++++++++++++++++++++++++++++++++++++++++- internal/api/routes.go | 21 ++++++-- web/assets/js/main.js | 3 +- 3 files changed, 133 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 263313a..ac84c93 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ relays: ### Set up a Bot -1. Navigate to the web interface at `http://localhost:8765` +1. Navigate to the web interface at `http://localhost:8765` (or your configured domain) 2. Log in with your Nostr extension (NIP-07) 3. Create a new bot by providing a name and optional keypair 4. Configure the posting schedule, media upload service, and relays @@ -123,6 +123,118 @@ relays: You can also trigger a post manually through the web interface +## Production Deployment + +### Nginx Configuration + +To serve Nostr Poster behind an Nginx reverse proxy with HTTPS, use the following configuration: + +```nginx +server { + listen 80; + server_name your-domain.com; + + # Redirect HTTP to HTTPS + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl; + server_name your-domain.com; + + # SSL configuration + ssl_certificate /path/to/your/fullchain.pem; + ssl_certificate_key /path/to/your/privkey.pem; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options SAMEORIGIN; + + # Proxy settings + location / { + proxy_pass http://localhost:8765; + 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; + + # WebSocket support (for Nostr connections) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeout settings for long-lived connections + proxy_read_timeout 86400; + proxy_send_timeout 86400; + } +} +``` + +Make sure to replace `your-domain.com` with your actual domain name and update the SSL certificate paths accordingly. + +### Systemd Service + +To run Nostr Poster as a system service that starts automatically on boot, create a systemd service file: + +1. Create a systemd service file: + +```bash +sudo nano /etc/systemd/system/nostr-poster.service +``` + +2. Add the following content: + +```ini +[Unit] +Description=Nostr Poster Bot Service +After=network.target + +[Service] +Type=simple +User=nostr +WorkingDirectory=/path/to/nostr-poster +ExecStart=/path/to/nostr-poster/build/bin/nostr-poster +Restart=on-failure +RestartSec=5 +StandardOutput=journal +StandardError=journal +Environment=GIN_MODE=release + +# Hardening measures +PrivateTmp=true +ProtectSystem=full +NoNewPrivileges=true +ProtectHome=true + +[Install] +WantedBy=multi-user.target +``` + +Replace `/path/to/nostr-poster` with the actual path to your installation, and `nostr` with the user you want to run the service as. + +3. Enable and start the service: + +```bash +sudo systemctl daemon-reload +sudo systemctl enable nostr-poster +sudo systemctl start nostr-poster +``` + +4. Check the status of the service: + +```bash +sudo systemctl status nostr-poster +``` + +5. View logs: + +```bash +sudo journalctl -u nostr-poster -f +``` + ## NIPs Supported - NIP-01: Basic protocol flow diff --git a/internal/api/routes.go b/internal/api/routes.go index b47abe1..a5fe932 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -44,7 +44,22 @@ func NewAPI( globalRelayService *GlobalRelayService, // Changed from colon to comma ) *API { router := gin.Default() - + + // Add CORS middleware + router.Use(func(c *gin.Context) { + c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") + c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Authorization, Content-Type") + + // Handle preflight requests + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(http.StatusOK) + return + } + + c.Next() + }) + api := &API{ router: router, logger: logger, @@ -53,10 +68,10 @@ func NewAPI( scheduler: scheduler, globalRelayService: globalRelayService, // Added this missing field } - + // Set up routes api.setupRoutes() - + return api } diff --git a/web/assets/js/main.js b/web/assets/js/main.js index 4c4a71f..973d98b 100644 --- a/web/assets/js/main.js +++ b/web/assets/js/main.js @@ -87,7 +87,8 @@ document.addEventListener('DOMContentLoaded', () => { * Global State * -------------------------------------------------- */ let currentUser = null; - const API_ENDPOINT = 'http://localhost:8765'; // <--- If your server is at http://localhost:8765, then use that. Example: 'http://localhost:8765' + // Define API_ENDPOINT using relative URLs to fix CORS issues when running behind a proxy + const API_ENDPOINT = ''; /* ---------------------------------------------------- * On page load, check if already logged in