refactor: switch from FTPS/lftp to rsync for deployment
Replace the FTPS-based deployment approach with rsync over SSH for more reliable and efficient mirroring of the Hugo site. This change addresses issues with the previous approach and provides true mirror behavior. Key changes: - Replace lftp with rsync for file synchronization - Add --delete flag for true mirror behavior (removes stale remote files) - Simplify authentication to use SSH keys only (no password needed) - Update all documentation and OpenSpec artifacts - Add .envrc to gitignore for direnv users Environment variables: - SSH_USER: SSH username (required) - SSH_HOST: server hostname (required) - SSH_PORT: SSH port (optional, defaults to 22) - REMOTE_ROOT: remote directory path (optional, defaults to /httpsdocs) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+86
-53
@@ -1,28 +1,28 @@
|
||||
# Deployment Guide
|
||||
|
||||
This guide explains how to deploy the Hugo-built static site to the production server at www.markusgraf.ch.
|
||||
This guide explains how to deploy the Hugo-built static site to the production server via rsync over SSH, properly mirroring the content.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before deploying, ensure you have:
|
||||
|
||||
1. **Built the site**: Run `hugo build` to generate the `public/` directory
|
||||
2. **lftp installed**: The deployment script requires the `lftp` command-line tool
|
||||
3. **FTPS credentials**: You need the FTPS username and password for the server
|
||||
2. **SSH access configured**: You need SSH access to your server with key-based authentication
|
||||
3. **Rsync available**: The deployment script requires the `rsync` command-line tool
|
||||
|
||||
### Installing lftp
|
||||
### Installing Rsync
|
||||
|
||||
If `lftp` is not installed on your system:
|
||||
Rsync is typically pre-installed on most systems, but if needed:
|
||||
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install lftp
|
||||
sudo apt-get install rsync
|
||||
|
||||
# macOS
|
||||
brew install lftp
|
||||
# macOS (usually pre-installed)
|
||||
# No action needed, or: brew install rsync
|
||||
|
||||
# Fedora
|
||||
sudo dnf install lftp
|
||||
sudo dnf install rsync
|
||||
```
|
||||
|
||||
## Deployment Process
|
||||
@@ -39,14 +39,16 @@ This generates the static files in the `public/` directory.
|
||||
|
||||
### 2. Set Environment Variables
|
||||
|
||||
Set the FTPS credentials as environment variables:
|
||||
Set the SSH connection details as environment variables:
|
||||
|
||||
```bash
|
||||
export FTPS_USER='gurix'
|
||||
export FTPS_PASSWORD='your-password-here'
|
||||
export SSH_USER='your-username'
|
||||
export SSH_HOST='your-server.com'
|
||||
export SSH_PORT='22' # Optional, defaults to 22
|
||||
export REMOTE_ROOT='/httpsdocs' # Optional, defaults to /httpsdocs
|
||||
```
|
||||
|
||||
**Important**: Never commit passwords to version control. Credentials should only be stored as environment variables.
|
||||
**Important**: Ensure SSH key-based authentication is set up for password-less access.
|
||||
|
||||
### 3. Run the Deployment Script
|
||||
|
||||
@@ -58,8 +60,9 @@ Execute the deployment script:
|
||||
|
||||
The script will:
|
||||
- Check that all prerequisites are met
|
||||
- Connect to www.markusgraf.ch via FTPS
|
||||
- Upload all files from `public/` to `httpsdocs/` on the server
|
||||
- Connect to your server via rsync over SSH
|
||||
- Sync all files from `public/` to the specified remote directory
|
||||
- Delete remote files that don't exist locally (true mirror behavior)
|
||||
- Display progress and completion status
|
||||
|
||||
### Complete Example
|
||||
@@ -70,9 +73,11 @@ Here's the full workflow:
|
||||
# Build the site
|
||||
hugo build
|
||||
|
||||
# Set credentials (only needed once per session)
|
||||
export FTPS_USER='gurix'
|
||||
export FTPS_PASSWORD='your-password'
|
||||
# Set connection details (only needed once per session)
|
||||
export SSH_USER='your-username'
|
||||
export SSH_HOST='your-server.com'
|
||||
export SSH_PORT='22' # Optional
|
||||
export REMOTE_ROOT='/httpsdocs' # Optional
|
||||
|
||||
# Deploy
|
||||
./scripts/deploy.sh
|
||||
@@ -82,20 +87,22 @@ export FTPS_PASSWORD='your-password'
|
||||
|
||||
The deployment script uses the following configuration:
|
||||
|
||||
- **Server**: www.markusgraf.ch
|
||||
- **Protocol**: FTPS (FTP over SSL/TLS)
|
||||
- **Username**: gurix
|
||||
- **Target Directory**: httpsdocs/
|
||||
- **Protocol**: rsync over SSH
|
||||
- **Default Port**: 22 (configurable via SSH_PORT)
|
||||
- **Default Target Directory**: /httpsdocs (configurable via REMOTE_ROOT)
|
||||
- **Source Directory**: public/
|
||||
- **Sync Behavior**: Mirror mode with `--delete` flag (removes remote files not present locally)
|
||||
|
||||
## Security Notes
|
||||
|
||||
### Credential Management
|
||||
### SSH Key-Based Authentication
|
||||
|
||||
- **Never** hardcode passwords in scripts or configuration files
|
||||
- **Never** commit passwords to version control
|
||||
- Use environment variables to pass credentials securely
|
||||
- The deployment script never displays passwords in its output
|
||||
The deployment script uses SSH/SCP, which supports key-based authentication:
|
||||
|
||||
- **Set up SSH keys**: Generate an SSH key pair and add your public key to the server's `~/.ssh/authorized_keys`
|
||||
- **Test SSH access**: Verify you can connect without a password: `ssh -p 22 user@server`
|
||||
- **No password required**: SCP will use your SSH keys automatically
|
||||
- **Never** commit private keys to version control
|
||||
|
||||
### Optional: Using .env Files
|
||||
|
||||
@@ -103,7 +110,10 @@ For convenience, you can create a `.env` file (which is ignored by git):
|
||||
|
||||
```bash
|
||||
# .env
|
||||
FTPS_PASSWORD=your-password
|
||||
export SSH_USER='your-username'
|
||||
export SSH_HOST='your-server.com'
|
||||
export SSH_PORT='22'
|
||||
export REMOTE_ROOT='/httpsdocs'
|
||||
```
|
||||
|
||||
Then source it before deployment:
|
||||
@@ -121,58 +131,81 @@ source .env
|
||||
|
||||
**Solution**: Run `hugo build` before deploying.
|
||||
|
||||
### Error: "lftp is not installed"
|
||||
### Error: "rsync is not installed"
|
||||
|
||||
**Cause**: The `lftp` tool is not available on your system.
|
||||
**Cause**: The `rsync` tool is not available on your system.
|
||||
|
||||
**Solution**: Install lftp using the instructions above.
|
||||
**Solution**: Install rsync using the instructions above.
|
||||
|
||||
### Error: "FTPS_PASSWORD environment variable is not set"
|
||||
### Error: "SSH_USER environment variable is not set"
|
||||
|
||||
**Cause**: The password environment variable hasn't been set.
|
||||
**Cause**: Required environment variables haven't been set.
|
||||
|
||||
**Solution**: Run `export FTPS_PASSWORD='your-password'` before deploying.
|
||||
**Solution**: Set the required variables:
|
||||
```bash
|
||||
export SSH_USER='your-username'
|
||||
export SSH_HOST='your-server.com'
|
||||
```
|
||||
|
||||
### Connection Failures
|
||||
### SSH Connection Failures
|
||||
|
||||
**Cause**: Network issues or incorrect credentials.
|
||||
**Cause**: SSH authentication issues or network problems.
|
||||
|
||||
**Solutions**:
|
||||
- Verify your internet connection
|
||||
- Check that the password is correct
|
||||
- Ensure the server (www.markusgraf.ch) is accessible
|
||||
- Verify firewall settings aren't blocking FTPS (port 21)
|
||||
- Verify you can connect manually: `ssh -p 22 user@server`
|
||||
- Check that your SSH key is added to the server's `~/.ssh/authorized_keys`
|
||||
- Ensure your internet connection is working
|
||||
- Verify the server is accessible
|
||||
- Check firewall settings aren't blocking SSH (default port 22)
|
||||
|
||||
### Partial Upload Failures
|
||||
### Permission Denied on Remote Directory
|
||||
|
||||
**Cause**: Network interruption during upload.
|
||||
**Cause**: User doesn't have write permissions to the target directory.
|
||||
|
||||
**Solution**: Simply run the deployment script again. The `mirror` command will resume and complete the upload.
|
||||
**Solution**:
|
||||
- Verify the REMOTE_ROOT directory exists on the server
|
||||
- Ensure your SSH user has write permissions to that directory
|
||||
- Contact your server administrator if needed
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Testing Without Deploying
|
||||
### Testing SSH Connection
|
||||
|
||||
To test the script without actually uploading files, you can modify the `deploy()` function temporarily to use the `--dry-run` flag:
|
||||
To test your SSH connection before deploying:
|
||||
|
||||
```bash
|
||||
mirror --reverse --delete --verbose --parallel=3 --dry-run $SOURCE_DIR $TARGET_DIR;
|
||||
# Test basic SSH connection
|
||||
ssh -p "${SSH_PORT:-22}" "$SSH_USER@$SSH_HOST"
|
||||
|
||||
# Test that you can write to the target directory
|
||||
ssh -p "${SSH_PORT:-22}" "$SSH_USER@$SSH_HOST" "touch ${REMOTE_ROOT:-/httpsdocs}/test.txt && rm ${REMOTE_ROOT:-/httpsdocs}/test.txt"
|
||||
```
|
||||
|
||||
### Deployment from CI/CD
|
||||
|
||||
For automated deployments from CI/CD pipelines:
|
||||
|
||||
1. Store `FTPS_PASSWORD` as a secret in your CI/CD system
|
||||
2. Ensure the CI/CD environment has `lftp` installed
|
||||
3. Run the deployment script after successful builds
|
||||
1. Set up SSH key-based authentication for your CI/CD runner
|
||||
2. Store `SSH_USER` and `SSH_HOST` as environment variables or secrets
|
||||
3. Ensure the CI/CD environment has `rsync` installed
|
||||
4. Run the deployment script after successful builds
|
||||
|
||||
Example GitHub Actions workflow snippet:
|
||||
|
||||
```yaml
|
||||
- name: Setup SSH key
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Deploy to server
|
||||
env:
|
||||
FTPS_PASSWORD: ${{ secrets.FTPS_PASSWORD }}
|
||||
SSH_USER: ${{ secrets.SSH_USER }}
|
||||
SSH_HOST: ${{ secrets.SSH_HOST }}
|
||||
SSH_PORT: ${{ secrets.SSH_PORT }}
|
||||
REMOTE_ROOT: ${{ secrets.REMOTE_ROOT }}
|
||||
run: ./scripts/deploy.sh
|
||||
```
|
||||
|
||||
@@ -180,7 +213,7 @@ Example GitHub Actions workflow snippet:
|
||||
|
||||
If you encounter issues not covered in this guide:
|
||||
|
||||
1. Check the server logs
|
||||
2. Verify network connectivity to www.markusgraf.ch
|
||||
3. Ensure the `httpsdocs/` directory exists on the server
|
||||
1. Test SSH connectivity manually: `ssh user@server`
|
||||
2. Check server logs for authentication or permission issues
|
||||
3. Verify the target directory exists and has correct permissions
|
||||
4. Contact your hosting provider for server-side issues
|
||||
|
||||
Reference in New Issue
Block a user