Deploy Go App to AWS EC2 with Systemd
Complete guide to deploy and run your Go application as a systemd service
This guide walks you through deploying your Go application to an AWS EC2 instance and running it as a systemd service. Systemd ensures your application starts automatically on boot, restarts on crashes, and can be easily managed.
Prerequisites
- AWS account with EC2 access
- Go application ready to deploy
- SSH access to EC2 instance
- Basic knowledge of Linux commands
Launch EC2 Instance
Launch an EC2 instance using Amazon Linux 2 or Ubuntu Server. For this guide, we'll use Ubuntu.
AWS Console Steps:
- Go to EC2 Dashboard → Launch Instance
- Choose Ubuntu Server 22.04 LTS (or latest)
- Select instance type (t2.micro for free tier, t3.small for production)
- Configure security group: Open port 22 (SSH) and your app port (e.g., 8080)
- Launch instance and download the key pair (.pem file)
Connect to your instance:
# Set correct permissions for key file
chmod 400 your-key.pem
# SSH into the instance
ssh -i your-key.pem ubuntu@YOUR_EC2_IP_ADDRESS
Install Go on EC2
Install Go on your EC2 instance:
# Update package list
sudo apt update
# Install Go (Ubuntu/Debian)
sudo apt install golang-go -y
# Verify installation
go version
# Set GOPATH and GOROOT (add to ~/.bashrc or ~/.profile)
echo 'export GOPATH=$HOME/go' >> ~/.bashrc
echo 'export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin' >> ~/.bashrc
source ~/.bashrc
Note: For latest Go version, download from golang.org/dl and extract to /usr/local.
Transfer Your Go Application
Copy your Go application to the EC2 instance. Option 1: Using SCP (from your local machine):
# From your local machine, compress and transfer
tar -czf app.tar.gz your-go-project/
scp -i your-key.pem app.tar.gz ubuntu@YOUR_EC2_IP:/home/ubuntu/
# SSH into EC2 and extract
ssh -i your-key.pem ubuntu@YOUR_EC2_IP
cd /home/ubuntu
tar -xzf app.tar.gz
cd your-go-project
Option 2: Clone from Git (if your code is in a repository):
# On EC2 instance
cd /home/ubuntu
git clone https://github.com/yourusername/your-go-project.git
cd your-go-project
Build the Go Application
Build your Go application on the EC2 instance:
# Navigate to your project
cd /home/ubuntu/your-go-project
# Download dependencies
go mod download
# Build the application
go build -o myapp cmd/server/main.go
# Or build for production (optimized)
go build -ldflags="-s -w" -o myapp cmd/server/main.go
# Test if it runs
./myapp
Create a directory for your application:
# Create app directory
sudo mkdir -p /opt/myapp
sudo chown ubuntu:ubuntu /opt/myapp
# Copy binary and config files
cp myapp /opt/myapp/
cp -r configs /opt/myapp/ # if you have config files
# Make it executable
sudo chmod +x /opt/myapp/myapp
Create Systemd Service File
Create a systemd service file to manage your application:
# Create service file
sudo nano /etc/systemd/system/myapp.service
Add the following content (adjust paths and user as needed):
[Unit]
Description=My Go Application
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/myapp
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
# Environment variables (optional)
Environment="PORT=8080"
Environment="ENV=production"
# Security settings
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Key settings explained:
Restart=always- Automatically restart on crashRestartSec=5- Wait 5 seconds before restartingStandardOutput=journal- Logs go to systemd journalUser=ubuntu- Run as ubuntu user (use non-root user)
Enable and Start the Service
Reload systemd, enable, and start your service:
# Reload systemd daemon
sudo systemctl daemon-reload
# Enable service to start on boot
sudo systemctl enable myapp
# Start the service
sudo systemctl start myapp
# Check service status
sudo systemctl status myapp
# View logs
sudo journalctl -u myapp -f
The service should now be running. Test it by accessing http://YOUR_EC2_IP:8080.
Common Systemd Commands
Service Management
# Start service
sudo systemctl start myapp
# Stop service
sudo systemctl stop myapp
# Restart service
sudo systemctl restart myapp
# Reload service (if supported)
sudo systemctl reload myapp
# Check status
sudo systemctl status myapp
Logs and Debugging
# View recent logs
sudo journalctl -u myapp
# Follow logs (like tail -f)
sudo journalctl -u myapp -f
# View last 100 lines
sudo journalctl -u myapp -n 100
# View logs since today
sudo journalctl -u myapp --since today
Security Best Practices
-
Run as non-root user: Always set
User=ubuntuin the service file. Never run your app as root. - Firewall configuration: Only open necessary ports in EC2 security group. Use AWS Security Groups to restrict access.
- Use environment variables: Store sensitive data (API keys, DB passwords) in environment variables, not in code.
- Enable HTTPS: Use a reverse proxy like Nginx with Let's Encrypt certificates for HTTPS.
- Regular updates: Keep your EC2 instance and Go application updated with security patches.
Optional: Nginx Reverse Proxy
Set up Nginx as a reverse proxy to serve your app on port 80/443 and handle SSL:
# Install Nginx
sudo apt install nginx -y
# Create Nginx config
sudo nano /etc/nginx/sites-available/myapp
# Add this configuration:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:8080;
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;
}
}
# Enable site
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t # Test configuration
sudo systemctl restart nginx
Troubleshooting
Service fails to start:
- Check logs:
sudo journalctl -u myapp -n 50 - Verify binary path and permissions
- Check if port is already in use:
sudo netstat -tulpn | grep 8080
Can't access from outside:
- Check EC2 Security Group - ensure port is open
- Verify app is listening on 0.0.0.0, not just localhost
- Check Ubuntu firewall:
sudo ufw status
Permission denied errors:
- Ensure user in service file has read/execute permissions
- Check file ownership:
ls -la /opt/myapp/
Quick Reference
Service File Location:
/etc/systemd/system/myapp.service
Application Directory:
/opt/myapp/
View Logs:
sudo journalctl -u myapp -f
Restart Service:
sudo systemctl restart myapp