diff --git a/.infra/kube/nfs.yaml b/.infra/kube/nfs.yaml new file mode 100644 index 0000000..68a4fae --- /dev/null +++ b/.infra/kube/nfs.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: nfs-tusd + namespace: tus +spec: + capacity: + storage: 20Gi + accessModes: + - ReadWriteMany + nfs: + # FIXME: use the right IP + server: NFS_SERVER_IP + path: "/" diff --git a/.infra/kube/tusd-kube.yaml b/.infra/kube/tusd-kube.yaml index c44db1a..cffd91f 100644 --- a/.infra/kube/tusd-kube.yaml +++ b/.infra/kube/tusd-kube.yaml @@ -1,15 +1,15 @@ -apiVersion: v1 kind: PersistentVolumeClaim +apiVersion: v1 metadata: - name: tusd + name: nfs-tusd namespace: tus spec: accessModes: - - ReadWriteOnce + - ReadWriteMany + storageClassName: "" resources: requests: - storage: 50Gi - storageClassName: standard + storage: 20Gi --- apiVersion: extensions/v1beta1 kind: Deployment @@ -22,7 +22,7 @@ spec: strategy: type: RollingUpdate rollingUpdate: - maxSurge: 1 + maxSurge: 2 maxUnavailable: 0 template: metadata: @@ -36,23 +36,22 @@ spec: name: tusd resources: limits: - cpu: 0.7 memory: "2Gi" requests: - cpu: 0.5 memory: "1Gi" ports: - - containerPort: 8080 + - name: tusd-web + containerPort: 8080 securityContext: - runAsUser: 1000 - fsGroup: 1000 + runAsUser: 0 + fsGroup: 0 volumeMounts: - name: tusd-disk mountPath: /srv/tusd-data volumes: - name: tusd-disk persistentVolumeClaim: - claimName: tusd + claimName: nfs-tusd --- apiVersion: v1 kind: Service @@ -61,7 +60,8 @@ metadata: namespace: tus spec: ports: - - port: 80 + - name: tusd-web + port: 80 targetPort: 8080 protocol: TCP selector: @@ -75,6 +75,14 @@ metadata: annotations: kubernetes.io/tls-acme: "true" kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/configuration-snippet: | + # Security: Don't allow people to upload html and then have browsers parse it + if ($uri ~ \.(?!(jpe?g|gif|png|webp|webm|mp4|mpg|avi|3gp|wav|mp3))$) { + add_header Content-Type application/octet-stream; + add_header Content-Disposition "attachment; filename=$basename"; + add_header X-Download-Options noopen; + add_header X-Content-Type-Options nosniff; + } nginx.ingress.kubernetes.io/proxy-body-size: 0m nginx.ingress.kubernetes.io/proxy-connect-timeout: "300" nginx.ingress.kubernetes.io/proxy-read-timeout: "300" diff --git a/.scripts/deploy_gcloud.sh b/.scripts/deploy_gcloud.sh index edc720c..0316ede 100755 --- a/.scripts/deploy_gcloud.sh +++ b/.scripts/deploy_gcloud.sh @@ -30,7 +30,9 @@ kubectl config set-credentials travis --token=$SA_TOKEN kubectl config set-context travis --cluster=$CLUSTER_NAME --user=travis --namespace=tus kubectl config use-context travis - +sed -i "s#NFS_SERVER_IP#${NFS_SERVER_IP}#" ./.infra/kube/nfs.yaml +kubectl apply -f "${__root}/.infra/kube/nfs.yaml" +sleep 10s # This cost me some precious debugging time. kubectl apply --validate=false -f "${__root}/.infra/kube/tusd-kube.yaml" diff --git a/README.md b/README.md index 1133d4f..6f6a41d 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,11 @@ specifies a flexible method to upload files to remote servers using HTTP. The special feature is the ability to pause and resume uploads at any moment allowing to continue seamlessly after e.g. network interruptions. +It is capable of accepting uploads with arbitrary sizes and storing them locally +on disk, on Google Cloud Storage or on AWS S3 (or any other S3-compatible +storage system). Due to its modularization and extensibility, support for +nearly any other cloud provider could easily be added to tusd. + **Protocol version:** 1.0.0 ## Getting started @@ -26,23 +31,102 @@ Windows in various formats of the ### Compile from source -**Requirements:** - -* [Go](http://golang.org/doc/install) (1.5 or newer) - -**Running tusd from source:** - -Clone the git repository and `cd` into it. +The only requirement for building tusd is [Go](http://golang.org/doc/install) 1.5 or newer. +If you meet this criteria, you can clone the git repository and build the binary: ```bash git clone git@github.com:tus/tusd.git cd tusd +go build -o tusd cmd/tusd/main ``` -Now you can run tusd: +## Running tusd -```bash -go run cmd/tusd/main.go +Start the tusd upload server is as simple as invoking a single command. For example, following +snippet demostrates how to start a tusd process which accepts tus uploads at +`http://localhost:1080/files/` and stores them locally in the `./data` directory: + +``` +$ tusd -dir ./data +[tusd] Using './data' as directory storage. +[tusd] Using 0.00MB as maximum size. +[tusd] Using 0.0.0.0:1080 as address to listen. +[tusd] Using /files/ as the base path. +[tusd] Using /metrics as the metrics path. +``` + +Alternatively, if you want to store the uploads on an AWS S3 bucket, you only have to specify +the bucket and provide the corresponding access credentials and region information using +environment variables (if you want to use a S3-compatible store, use can use the `-s3-endpoint` +option): + +``` +$ export AWS_ACCESS_KEY_ID=xxxxx +$ export AWS_SECRET_ACCESS_KEY=xxxxx +$ export AWS_REGION=eu-west-1 +$ tusd -s3-bucket my-test-bucket.com +[tusd] Using 's3://my-test-bucket.com' as S3 bucket for storage. +[tusd] Using 0.00MB as maximum size. +[tusd] Using 0.0.0.0:1080 as address to listen. +[tusd] Using /files/ as the base path. +[tusd] Using /metrics as the metrics path. +``` + +Furthermore, tusd also has support for storing uploads on Google Cloud Storage. In order to +enable this feature, supply the path to your account file containing the necessary credentials: + +``` +$ export GCS_SERVICE_ACCOUNT_FILE=./account.json +$ tusd -gcs-bucket my-test-bucket.com +[tusd] Using 'gcs://my-test-bucket.com' as GCS bucket for storage. +[tusd] Using 0.00MB as maximum size. +[tusd] Using 0.0.0.0:1080 as address to listen. +[tusd] Using /files/ as the base path. +[tusd] Using /metrics as the metrics path. +``` + +Besides these simple examples, tusd can be easily configured using a variety of command line +options: + +``` +$ tusd -help +Usage of tusd: + -base-path string + Basepath of the HTTP server (default "/files/") + -behind-proxy + Respect X-Forwarded-* and similar headers which may be set by proxies + -dir string + Directory to store uploads in (default "./data") + -expose-metrics + Expose metrics about tusd usage (default true) + -gcs-bucket string + Use Google Cloud Storage with this bucket as storage backend (requires the GCS_SERVICE_ACCOUNT_FILE environment variable to be set) + -hooks-dir string + Directory to search for available hooks scripts + -hooks-http string + An HTTP endpoint to which hook events will be sent to + -hooks-http-backoff int + Number of seconds to wait before retrying each retry (default 1) + -hooks-http-retry int + Number of times to retry on a 500 or network timeout (default 3) + -host string + Host to bind HTTP server to (default "0.0.0.0") + -max-size int + Maximum size of a single upload in bytes + -metrics-path string + Path under which the metrics endpoint will be accessible (default "/metrics") + -port string + Port to bind HTTP server to (default "1080") + -s3-bucket string + Use AWS S3 with this bucket as storage backend (requires the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION environment variables to be set) + -s3-endpoint string + Endpoint to use S3 compatible implementations like minio (requires s3-bucket to be pass) + -store-size int + Size of space allowed for storage + -timeout int + Read timeout for connections in milliseconds. A zero value means that reads will not timeout (default 30000) + -version + Print tusd version information ``` ## Using tusd manually