Overview
Manual deployment gives you full control over the build and runtime environment. This guide covers building from source, managing SSH keys, and running in production.
Prerequisites
Go 1.24 or higher
Git
Linux, macOS, or WSL on Windows
SSH client (for testing)
Build from Source
Clone the repository
git clone https://github.com/ab-70/ssh-portfolio.git
cd ssh-portfolio
Download dependencies
This downloads all required Go modules listed in go.mod.
Build the binary
go build -o ssh-portfolio .
This creates an executable named ssh-portfolio in the current directory.
Verify the build
Or check the binary exists:
Optimized Production Build
For production deployments, build with optimizations:
CGO_ENABLED = 0 go build -ldflags= "-s -w" -o ssh-portfolio .
Build flags explained:
CGO_ENABLED=0 - Disable CGO for static binary
-ldflags="-s -w" - Strip debug information (smaller binary)
-o ssh-portfolio - Output filename
Linux (amd64)
Linux (arm64)
macOS (Apple Silicon)
macOS (Intel)
GOOS = linux GOARCH = amd64 go build -o ssh-portfolio-linux-amd64 .
Generate SSH Host Keys
SSH Portfolio requires host keys for the SSH server. The application expects keys at .ssh/id_ed25519.
Generate ED25519 key pair
ssh-keygen -t ed25519 -f .ssh/id_ed25519 -N ""
-t ed25519 - Use ED25519 algorithm (modern, secure)
-f .ssh/id_ed25519 - Output file path
-N "" - Empty passphrase (required for automated servers)
Verify keys were created
You should see:
id_ed25519 - Private key
id_ed25519.pub - Public key
Set proper permissions
chmod 600 .ssh/id_ed25519
chmod 644 .ssh/id_ed25519.pub
SSH will refuse to use keys with incorrect permissions for security reasons.
The host key path is configured in main.go:38:
wish . WithHostKeyPath ( ".ssh/id_ed25519" ),
Create or edit config.yaml with your information:
name : "Your Name"
tagline : "Your professional tagline"
bio : "A brief bio about yourself"
links :
- name : "GitHub"
url : "https://github.com/yourusername"
- name : "Website"
url : "https://yourwebsite.com"
See the Configuration Guide for all available options.
Run the Application
Basic Run
By default, the server starts on 0.0.0.0:2222 (see main.go:25-26).
Custom Port
SSH_PORT = 3000 ./ssh-portfolio
The application reads the SSH_PORT environment variable (main.go:27-29):
port := "2222"
if p := os . Getenv ( "SSH_PORT" ); p != "" {
port = p
}
Background Process
Run in the background with nohup:
nohup ./ssh-portfolio > ssh-portfolio.log 2>&1 &
Test the Connection
Process Management with systemd
For production servers, use systemd to manage the SSH Portfolio service.
Create a systemd service file
sudo nano /etc/systemd/system/ssh-portfolio.service
Add service configuration
[Unit]
Description =SSH Portfolio Server
After =network.target
[Service]
Type =simple
User =portfolio
Group =portfolio
WorkingDirectory =/opt/ssh-portfolio
Environment = "SSH_PORT=2222"
ExecStart =/opt/ssh-portfolio/ssh-portfolio
Restart =always
RestartSec =5
StandardOutput =journal
StandardError =journal
SyslogIdentifier =ssh-portfolio
[Install]
WantedBy =multi-user.target
Create dedicated user
sudo useradd -r -s /bin/ false -d /opt/ssh-portfolio portfolio
Set up application directory
sudo mkdir -p /opt/ssh-portfolio/.ssh
sudo cp ssh-portfolio /opt/ssh-portfolio/
sudo cp config.yaml /opt/ssh-portfolio/
sudo cp -r .ssh/id_ed25519 * /opt/ssh-portfolio/.ssh/
sudo chown -R portfolio:portfolio /opt/ssh-portfolio
sudo chmod 600 /opt/ssh-portfolio/.ssh/id_ed25519
Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable ssh-portfolio
sudo systemctl start ssh-portfolio
Check service status
sudo systemctl status ssh-portfolio
Systemd Service Management
Start
Stop
Restart
Status
Logs
Disable
sudo systemctl start ssh-portfolio
Production Considerations
Port Configuration
Running on port 22 requires root privileges. Itβs recommended to use a higher port (>1024) or configure port forwarding.
Option 1: Run on high port (recommended)
SSH_PORT = 2222 ./ssh-portfolio
Option 2: Use iptables for port forwarding
sudo iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222
Option 3: Use setcap to bind privileged ports
sudo setcap 'cap_net_bind_service=+ep' /opt/ssh-portfolio/ssh-portfolio
Firewall Configuration
Ensure your firewall allows connections:
# UFW
sudo ufw allow 2222/tcp
# iptables
sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
Monitoring
Monitor your application logs:
# journalctl (systemd)
sudo journalctl -u ssh-portfolio -f
# Log file (nohup)
tail -f ssh-portfolio.log
Updates and Maintenance
To update your deployment:
Rebuild the binary
go build -o ssh-portfolio .
Restart the service
sudo systemctl restart ssh-portfolio
Security Best Practices
Run as a non-root user (shown in systemd example)
Use restrictive file permissions (600 for private keys)
Keep SSH host keys secure and backed up
Monitor logs for unusual activity
Keep Go and dependencies updated
Consider rate limiting at the firewall level
Backup Important Files
Regularly backup:
# Backup configuration and keys
tar czf ssh-portfolio-backup.tar.gz \
config.yaml \
.ssh/id_ed25519 \
.ssh/id_ed25519.pub
Next Steps
Environment Variables Configure runtime settings
Docker Deployment Deploy with Docker