+3
.env.example
+3
.env.example
+5
-2
.gitignore
+5
-2
.gitignore
+29
-6
Dockerfile
+29
-6
Dockerfile
···
1
-
# Build stage
2
-
FROM rust:latest as builder
1
+
# Frontend build stage
2
+
FROM oven/bun:latest AS frontend-builder
3
+
4
+
WORKDIR /usr/src/frontend
5
+
6
+
# Copy frontend files
7
+
COPY frontend/package*.json ./
8
+
RUN bun install
9
+
10
+
COPY frontend/ ./
11
+
12
+
# Build frontend with production configuration
13
+
ARG API_URL=http://localhost:8080
14
+
ENV VITE_API_URL=${API_URL}
15
+
RUN bun run build
16
+
17
+
# Rust build stage
18
+
FROM rust:latest AS backend-builder
3
19
4
20
# Install PostgreSQL client libraries and SSL dependencies
5
21
RUN apt-get update && \
···
16
32
COPY migrations/ migrations/
17
33
COPY .sqlx/ .sqlx/
18
34
19
-
# Build your application
35
+
# Create static directory and copy frontend build
36
+
COPY --from=frontend-builder /usr/src/frontend/dist/ static/
37
+
38
+
# Build the application
20
39
RUN cargo build --release
21
40
22
41
# Runtime stage
···
30
49
WORKDIR /app
31
50
32
51
# Copy the binary from builder
33
-
COPY --from=builder /usr/src/app/target/release/simplelink /app/simplelink
52
+
COPY --from=backend-builder /usr/src/app/target/release/simplelink /app/simplelink
53
+
34
54
# Copy migrations folder for SQLx
35
-
COPY --from=builder /usr/src/app/migrations /app/migrations
55
+
COPY --from=backend-builder /usr/src/app/migrations /app/migrations
56
+
57
+
# Copy static files
58
+
COPY --from=backend-builder /usr/src/app/static /app/static
36
59
37
60
# Expose the port (this is just documentation)
38
61
EXPOSE 8080
···
42
65
ENV SERVER_PORT=8080
43
66
44
67
# Run the binary
45
-
CMD ["./simplelink"]
68
+
CMD ["./simplelink"]
+87
build.sh
+87
build.sh
···
1
+
#!/bin/bash
2
+
3
+
# Default values
4
+
API_URL="http://localhost:8080"
5
+
RELEASE_MODE=false
6
+
7
+
# Parse command line arguments
8
+
for arg in "$@"
9
+
do
10
+
case $arg in
11
+
api-domain=*)
12
+
API_URL="${arg#*=}"
13
+
shift
14
+
;;
15
+
--release)
16
+
RELEASE_MODE=true
17
+
shift
18
+
;;
19
+
esac
20
+
done
21
+
22
+
echo "Building project with API_URL: $API_URL"
23
+
echo "Release mode: $RELEASE_MODE"
24
+
25
+
# Check if cargo is installed
26
+
if ! command -v cargo &> /dev/null; then
27
+
echo "cargo is not installed. Please install Rust and cargo first."
28
+
exit 1
29
+
fi
30
+
31
+
# Check if npm is installed
32
+
if ! command -v npm &> /dev/null; then
33
+
echo "npm is not installed. Please install Node.js and npm first."
34
+
exit 1
35
+
fi
36
+
37
+
# Build frontend
38
+
echo "Building frontend..."
39
+
# Create .env file for Vite
40
+
echo "VITE_API_URL=$API_URL" > frontend/.env
41
+
42
+
# Install frontend dependencies and build
43
+
cd frontend
44
+
npm install
45
+
npm run build
46
+
cd ..
47
+
48
+
# Create static directory if it doesn't exist
49
+
mkdir -p static
50
+
51
+
# Clean existing static files
52
+
rm -rf static/*
53
+
54
+
# Copy built files to static directory
55
+
cp -r frontend/dist/* static/
56
+
57
+
# Build Rust project
58
+
echo "Building Rust project..."
59
+
if [ "$RELEASE_MODE" = true ]; then
60
+
cargo build --release
61
+
62
+
# Create release directory
63
+
mkdir -p release
64
+
65
+
# Copy binary and static files to release directory
66
+
cp target/release/simplelink release/
67
+
cp -r static release/
68
+
cp .env.example release/.env
69
+
70
+
# Create a tar archive
71
+
tar -czf release.tar.gz release/
72
+
73
+
echo "Release archive created: release.tar.gz"
74
+
else
75
+
cargo build
76
+
fi
77
+
78
+
echo "Build complete!"
79
+
echo "To run the project:"
80
+
if [ "$RELEASE_MODE" = true ]; then
81
+
echo "1. Extract release.tar.gz"
82
+
echo "2. Configure .env file"
83
+
echo "3. Run ./simplelink"
84
+
else
85
+
echo "1. Configure .env file"
86
+
echo "2. Run 'cargo run'"
87
+
fi
+36
-1
docker-compose.yml
+36
-1
docker-compose.yml
···
16
16
interval: 5s
17
17
timeout: 5s
18
18
retries: 5
19
+
networks:
20
+
- shortener-network
21
+
22
+
app:
23
+
build:
24
+
context: .
25
+
dockerfile: Dockerfile
26
+
args:
27
+
- API_URL=${API_URL:-http://localhost:8080}
28
+
container_name: shortener-app
29
+
ports:
30
+
- "8080:8080"
31
+
environment:
32
+
- DATABASE_URL=postgresql://shortener:shortener123@db:5432/shortener
33
+
- SERVER_HOST=0.0.0.0
34
+
- SERVER_PORT=8080
35
+
depends_on:
36
+
db:
37
+
condition: service_healthy
38
+
healthcheck:
39
+
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
40
+
interval: 30s
41
+
timeout: 10s
42
+
retries: 3
43
+
start_period: 40s
44
+
networks:
45
+
- shortener-network
46
+
deploy:
47
+
restart_policy:
48
+
condition: on-failure
49
+
max_attempts: 3
50
+
window: 120s
51
+
52
+
networks:
53
+
shortener-network:
54
+
driver: bridge
19
55
20
56
volumes:
21
57
shortener-data:
22
-
+2
src/main.rs
+2
src/main.rs
···
1
1
use actix_cors::Cors;
2
+
use actix_files as fs;
2
3
use actix_web::{web, App, HttpServer};
3
4
use anyhow::Result;
4
5
use simplelink::{handlers, AppState};
···
61
62
.route("/health", web::get().to(handlers::health_check)),
62
63
)
63
64
.service(web::resource("/{short_code}").route(web::get().to(handlers::redirect_to_url)))
65
+
.service(fs::Files::new("/", "./static").index_file("index.html"))
64
66
})
65
67
.workers(2)
66
68
.backlog(10_000)