Skip to main content
Version: 4.x

Best Practices

Security

There is no absolute security. Run Spug on the internal network without public access whenever possible; if public access is unavoidable, restrict the source IPs with a firewall and enable login MFA.

Spug disables an account on the next wrong password after 3 failed attempts (the counter resets after 24 hours), which makes brute-force logins impractical. Tokens are bound to the client IP: when the same Token is used from a different IP it expires and the user has to log in again (this can be disabled under Settings / Security Settings / Bind login to IP, which is not recommended).

Note

The client IP used by the token policy comes from the X-Real-IP and X-Forwarded-For headers set by Nginx, so Spug must see the real client IP and not the address of an upstream proxy. The recommended Docker setup handles this already. If you add another reverse proxy in front of the container's port 80, forward X-Forwarded-For, e.g. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; in Nginx.

When the real client IP cannot be verified (Spug sees an internal address), a warning is shown on login. If Spug is only used from the internal network, disable the check under System / Settings / Security Settings / Client IP verification.

Different actions on different hosts during a deploy

When an application is deployed to three hosts but a one-off step such as a database migration must run only once, use the global variables SPUG_HOST_ID or SPUG_HOST_NAME to run it on a single host:

if [ "$SPUG_HOST_NAME" = "192.168.10.100" ]; then
echo "exec sql"
fi

Command not found because of the default PATH

Spug runs commands over non-interactive SSH sessions, so the PATH may be incomplete. Extend it in the script when commands are not found:

# add the JDK to PATH
PATH=$PATH:/usr/local/jdk1.8.0_231/bin
java -jar xxx.jar

Alternatively run source /etc/profile or source ~/.bashrc at the top of the script.

Persistent project data

Applications often produce data that must survive releases, such as uploaded images or log files. With standard deploys every version lives in a fresh directory, so those files would disappear in the new version. Keep such data outside of the deploy directory and link it into the project with a symlink; the files stay in one shared place and every release only needs to recreate the link.

Error handling in scripts

Since v3 Spug no longer adds set -e, matching the default behaviour of shell scripts. If any failing command should abort the rest of the script, add set -e at the top yourself.

Switching users with su

Calling su directly hangs the script. Use a heredoc instead:

su - ubuntu << EOF
echo 'runs as ubuntu'
EOF

Separate build and release

For frequently released applications, build the version in the build repository first (or let the test deploy build it), verify it, and then pick the same Build repository version in the production deploy request. Test and production use exactly the same artifact and no time is wasted rebuilding.

Connecting external CI with pipelines

When builds happen in Jenkins / GitLab CI or another system, use a pipeline with a Data upload node for the artifact, Execute command nodes to unpack and restart, and a push node for the result; values that need human input (version, restart yes / no) come from a Parameter node at run time.

Automatic recovery from alerts

Create a scheduled task with the Monitor alert trigger and Alerting host as target, for example systemctl restart nginx when the process check fails, to get simple self-healing.