Introduction: Why Advanced Rust Deployment on VPS is a Necessity
Developing in Rust is only half the battle. The second, equally important part is reliable and secure deployment. Basic methods, such as manual compilation and running via cargo run, are not suitable for production. At an advanced level, automation, process isolation, monitoring, and ensuring high availability are required.
In this article, we will cover how to set up the deployment of a Rust application on a VPS using Docker, CI/CD (GitHub Actions), systemd for auto-start, and Nginx as a reverse proxy. All code examples are provided in Rust and Bash.
1. Preparing the VPS and Environment
1.1. Basic Server Setup
Assume you have a VPS running Ubuntu 22.04 LTS. First, update the packages and install the necessary tools:
sudo apt update && sudo apt upgrade -ysudo apt install -y curl git build-essential pkg-config libssl-devInstall Rust via rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shsource $HOME/.cargo/envrustc --version # verification1.2. Installing Docker
Docker will ensure environment isolation and reproducibility:
sudo apt install -y docker.iosudo systemctl enable --now dockersudo usermod -aG docker $USERnewgrp docker1.3. Installing Nginx
Nginx will act as a reverse proxy and load balancer:
sudo apt install -y nginxsudo systemctl enable --now nginx2. Containerizing the Rust Application with Docker
2.1. Multi-stage Build
To reduce the image size, we use a multi-stage build. Create a Dockerfile in the project root:
# Build stageFROM rust:1.75-slim-bookworm AS builderWORKDIR /appCOPY Cargo.toml Cargo.lock ./COPY src ./srcRUN cargo build --release
# Final stageFROM debian:bookworm-slimRUN apt update && apt install -y ca-certificates && rm -rf /var/lib/apt/lists/*WORKDIR /appCOPY --from=builder /app/target/release/my_app .EXPOSE 8080CMD ["./my_app"]Here, my_app is the name of your binary file. Make sure that Cargo.toml contains name = "my_app".
2.2. Building and Running the Container
docker build -t my_app:latest .docker run -d --name my_app -p 8080:8080 my_app:latestCheck that the application responds:
curl http://localhost:80803. Setting Up Auto-start and Monitoring (systemd + Docker Compose)
3.1. Docker Compose for Service Management
Create a docker-compose.yml:
version: '3.8'services: app: image: my_app:latest restart: always ports: - "127.0.0.1:8080:8080" environment: - RUST_LOG=info healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3Note: ports is bound to 127.0.0.1 so that external requests go only through Nginx.
3.2. Systemd Unit for Service Management
Create the file /etc/systemd/system/my_app.service:
[Unit]Description=My Rust ApplicationAfter=docker.serviceRequires=docker.service
[Service]Type=oneshotRemainAfterExit=yesWorkingDirectory=/opt/my_appExecStart=/usr/bin/docker compose up -dExecStop=/usr/bin/docker compose downUser=deployGroup=deploy
[Install]WantedBy=multi-user.targetEnable and start it:
sudo systemctl daemon-reloadsudo systemctl enable my_appsudo systemctl start my_app