# systemd unit for running the blog directly on a server (no Docker). # # Setup, assuming the checkout lives at /opt/yap-blog: # # sudo useradd --system --home-dir /opt/yap-blog --shell /usr/sbin/nologin yap-blog # cd /opt/yap-blog # npm ci && npm run build # .env must hold the production DATABASE_URL # npm run db:migrate && npm run db:seed # sudo chown -R yap-blog:yap-blog /opt/yap-blog # sudo cp deploy/yap-blog.service /etc/systemd/system/ # sudo systemctl daemon-reload # sudo systemctl enable --now yap-blog # # After deploying new code: npm ci && npm run build && npm run db:migrate, # then `sudo systemctl restart yap-blog`. Adjust the npm path in ExecStart # if `which npm` says something else (e.g. a nodesource or nvm install). [Unit] Description=Yap Blog (Next.js) Wants=network-online.target After=network-online.target postgresql.service [Service] Type=simple User=yap-blog Group=yap-blog WorkingDirectory=/opt/yap-blog # `next start` runs in production mode and reads .env from the working # directory. To keep secrets outside the checkout instead, delete .env and # uncomment: # EnvironmentFile=/etc/yap-blog/env ExecStart=/usr/bin/npm start Restart=on-failure RestartSec=3 # The filesystem is read-only to the service except where it writes: # uploaded images, and .next (Next.js keeps runtime caches/traces there). NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=read-only ReadWritePaths=/opt/yap-blog/uploads /opt/yap-blog/.next ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictSUIDSGID=true RestrictRealtime=true LockPersonality=true [Install] WantedBy=multi-user.target