diff --git a/.circleci/config.yml b/.circleci/config.yml index ccc266d..c375267 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,75 +1,9 @@ version: 2 -build_preconditions: &build_preconditions - filters: - branches: - only: - - master - - development - -deploy_preconditions: &deploy_preconditions - requires: - - build - filters: - branches: - only: - - master - - development - jobs: - build: - docker: - - image: docker:18-git - working_directory: ~/offen - steps: - - checkout - - setup_remote_docker - - restore_cache: - keys: - - v1-{{ .Branch }} - paths: - - /caches/website.tar - - run: - name: Load Docker image layer cache - command: | - set +o pipefail - docker load -i /caches/website.tar | true - - run: - name: Build application Docker image - command: | - if [ "${CIRCLE_BRANCH}" == "master" ]; then - export SITEURL="https://www.offen.dev" - export DOCKER_IMAGE_TAG="stable" - export ROBOTS_FILE="robots.txt.production" - else - export SITEURL="https://staging.offen.dev" - export DOCKER_IMAGE_TAG="latest" - export ROBOTS_FILE="robots.txt.staging" - fi - docker build --build-arg siteurl=$SITEURL --build-arg robots=$ROBOTS_FILE -t offen/website:$DOCKER_IMAGE_TAG -f build/Dockerfile . - - run: - name: Save Docker image layer cache - command: | - mkdir -p /caches - docker save -o /caches/website.tar offen/website - - save_cache: - key: v1-{{ .Branch }}-{{ epoch }} - paths: - - /caches/website.tar - - deploy: - name: Push application Docker image - command: | - if [ "${CIRCLE_BRANCH}" == "master" ]; then - export DOCKER_IMAGE_TAG="stable" - else - export DOCKER_IMAGE_TAG="latest" - fi - echo "$DOCKER_ACCESSTOKEN" | docker login --username $DOCKER_USER --password-stdin - docker push offen/website:$DOCKER_IMAGE_TAG - deploy: docker: - - image: circleci/golang:1.13 + - image: circleci/python:3.7 working_directory: ~/offen steps: - checkout @@ -77,34 +11,29 @@ jobs: - run: name: Install deployment dependencies command: | - sudo apt-get update && sudo apt-get install -qq -y python-pip libpython-dev - curl -O https://bootstrap.pypa.io/get-pip.py && sudo python get-pip.py sudo pip install -q awscli --upgrade - sudo pip install awsebcli --upgrade - run: - name: Define target environment + name: Build and deploy to S3 command: | if [ "${CIRCLE_BRANCH}" == "master" ]; then - echo 'export TARGET_ENVIRONMENT="production"' >> $BASH_ENV - echo 'export DOCKER_IMAGE_TAG="stable"' >> $BASH_ENV + export SITEURL="https://www.offen.dev" + export BUCKET="offen-dev-production" + export ROBOTS_FILE="robots.txt.production" else - echo 'export TARGET_ENVIRONMENT="staging"' >> $BASH_ENV - echo 'export DOCKER_IMAGE_TAG="latest"' >> $BASH_ENV + export SITEURL="https://staging.offen.dev" + export BUCKET="offen-dev-staging" + export ROBOTS_FILE="robots.txt.staging" fi - - run: - name: Run database migrations - command: docker run -it offen/offen:offen@sha256:4c0d2d5db9bc749d21ad8659008658bf25318074b7c813b0a694e64816df750d migrate -conn $(aws secretsmanager get-secret-value --secret-id $TARGET_ENVIRONMENT/postgresConnectionString | jq -r '.SecretString') - - run: - name: Deploy - command: | - cp Dockerrun.aws.json.$TARGET_ENVIRONMENT Dockerrun.aws.json - eb deploy + make build + aws s3 sync --delete ./output/. s3://$BUCKET workflows: version: 2 build_deploy: jobs: - - build: - <<: *build_preconditions - deploy: - <<: *deploy_preconditions + filters: + branches: + only: + - master + - development diff --git a/.ebignore b/.ebignore deleted file mode 100644 index 8f16f47..0000000 --- a/.ebignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!Dockerrun.aws.json diff --git a/.elasticbeanstalk/config.yml b/.elasticbeanstalk/config.yml deleted file mode 100644 index 222b50e..0000000 --- a/.elasticbeanstalk/config.yml +++ /dev/null @@ -1,20 +0,0 @@ -branch-defaults: - master: - environment: production - group_suffix: null - development: - environment: staging - group_suffix: null -global: - application_name: offen - branch: null - default_ec2_keyname: aws-eb - default_platform: Multi-container Docker 18.06.1-ce (Generic) - default_region: eu-central-1 - include_git_submodules: true - instance_profile: null - platform_name: null - platform_version: null - repository: null - sc: null - workspace_type: Application diff --git a/Dockerrun.aws.json.production b/Dockerrun.aws.json.production deleted file mode 100644 index ec1dba1..0000000 --- a/Dockerrun.aws.json.production +++ /dev/null @@ -1,52 +0,0 @@ -{ - "AWSEBDockerrunVersion": 2, - "containerDefinitions": [ - { - "name": "proxy", - "image": "offen/website:stable", - "essential": true, - "memory": 128, - "portMappings": [ - { - "hostPort": 80, - "containerPort": 80 - } - ], - "dependsOn": [ - { - "containerName": "server", - "condition": "START" - } - ], - "links": ["server"], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-create-group": true, - "awslogs-group": "production", - "awslogs-region": "eu-central-1", - "awslogs-stream-prefix": "proxy" - } - } - }, - { - "name": "server", - "image": "offen/offen@sha256:4c0d2d5db9bc749d21ad8659008658bf25318074b7c813b0a694e64816df750d", - "essential": true, - "memory": 256, - "command": ["serve"], - "environment": [ - { "name": "OFFEN_SERVER_REVERSEPROXY", "value": "1" } - ], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-create-group": true, - "awslogs-group": "production", - "awslogs-region": "eu-central-1", - "awslogs-stream-prefix": "server" - } - } - } - ] -} diff --git a/Dockerrun.aws.json.staging b/Dockerrun.aws.json.staging deleted file mode 100644 index 2125921..0000000 --- a/Dockerrun.aws.json.staging +++ /dev/null @@ -1,53 +0,0 @@ -{ - "AWSEBDockerrunVersion": 2, - "volumes": [], - "containerDefinitions": [ - { - "name": "proxy", - "image": "offen/website:latest", - "essential": true, - "memory": 128, - "portMappings": [ - { - "hostPort": 80, - "containerPort": 80 - } - ], - "dependsOn": [ - { - "containerName": "server", - "condition": "START" - } - ], - "links": ["server"], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-create-group": true, - "awslogs-group": "staging", - "awslogs-region": "eu-central-1", - "awslogs-stream-prefix": "proxy" - } - } - }, - { - "name": "server", - "image": "offen/offen@sha256:4c0d2d5db9bc749d21ad8659008658bf25318074b7c813b0a694e64816df750d", - "essential": true, - "memory": 256, - "command": ["serve"], - "environment": [ - { "name": "OFFEN_SERVER_REVERSEPROXY", "value": "1" } - ], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-create-group": true, - "awslogs-group": "staging", - "awslogs-region": "eu-central-1", - "awslogs-stream-prefix": "server" - } - } - } - ] -} diff --git a/Makefile b/Makefile index 93fa809..ff62038 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,11 @@ help: @echo " setup" @echo " Build the development containers and install dependencies." @echo " update" - @echo " Install / update dependencies in the containers." - @echo " bootstrap" - @echo " Set up and seed databases." - @echo " **IMPORTANT**: this wipes any existing data in your local database." + @echo " Install / update dependencies in the development containers." @echo " build" - @echo " Build the production images." + @echo " Build the production assets." -setup: dev-build update howto +setup: dev-build update dev-build: @docker-compose build @@ -17,32 +14,20 @@ dev-build: up: @docker-compose up -howto: - @echo "Successfully built containers and installed dependencies." - @echo "If this is your initial setup, you can run 'make bootstrap' next" - @echo "to create and seed the database." - -bootstrap: - @echo "Bootstrapping Server service ..." - @docker-compose run server bootstrap - @echo "" - @echo "You can now log into the development backend using the following credentials:" - @echo "" - @echo "Email: develop@offen.dev" - @echo "Password: develop" - @echo "" - update: @echo "Installing / updating dependencies ..." @docker-compose run homepage pip install --user -r requirements.txt - @echo "Applying pending database migrations ..." - @docker-compose run server migrate + @echo "Successfully built containers and installed dependencies." -DOCKER_IMAGE_TAG ?= local ROBOTS_FILE ?= robots.txt.staging SITEURL ?= http://localhost:8000 build: - @docker build --build-arg siteurl=${SITEURL} --build-arg robots=${ROBOTS_FILE} -t offen/website:${DOCKER_IMAGE_TAG} -f build/Dockerfile . + @docker build --build-arg siteurl=${SITEURL} -t offen/website -f build/Dockerfile . + @rm -rf output && mkdir output + @docker create --entrypoint=bash -it --name assets offen/website + @docker cp assets:/code/homepage/output/. ./output/ + @cp build/${ROBOTS_FILE} ./output/robots.txt + @docker rm assets -.PHONY: setup build bootstrap build +.PHONY: setup build up diff --git a/build/Dockerfile b/build/Dockerfile index 7b4858c..518c59e 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,29 +1,19 @@ -FROM nikolaik/python-nodejs:python3.7-nodejs10 as homepage +FROM nikolaik/python-nodejs:python3.7-nodejs10 + +ENV PATH "/root/.local/bin:$PATH" +ENV NODE_PATH="/usr/lib/node_modules" ARG siteurl ENV SITEURL=$siteurl -COPY ./homepage /code/homepage - RUN npm install -g postcss-cli@^6.1.3 autoprefixer@^9.7.0 svgo@^1.3.0 RUN apt-get update \ && apt-get install -y libjpeg-progs optipng \ && rm -rf /var/lib/apt/lists/* WORKDIR /code/homepage -ENV PATH "/root/.local/bin:$PATH" -ENV NODE_PATH="/usr/lib/node_modules" +COPY ./homepage/requirements.txt /code/homepage/requirements.txt RUN pip install --user -r requirements.txt -RUN make publish -FROM nginx:1.17-alpine -LABEL maintainer="mail@offen.dev" - -ARG robots -ENV ROBOTS_FILE=$robots - -COPY --from=homepage /code/homepage/output /www/data -COPY ./build/$ROBOTS_FILE /www/data/robots.txt -COPY ./build/nginx.conf /etc/nginx/nginx.conf - -EXPOSE 80 +COPY ./homepage /code/homepage +RUN make publish && rm -rf output/theme/.webassets-cache diff --git a/build/nginx.conf b/build/nginx.conf deleted file mode 100644 index 1e31189..0000000 --- a/build/nginx.conf +++ /dev/null @@ -1,96 +0,0 @@ -events {} - -http { - gzip on; - gzip_types *; - gzip_comp_level 2; - gzip_min_length 1000; - gzip_proxied expired no-cache no-store private auth; - - include mime.types; - upstream server { - server server:3000; - } - - map $request_uri $expires { - default off; - "~-[0-9a-z]{10}\.js$" 365d; - "~*(woff|woff2|ttf|eot)$" 365d; - } - - map $sent_http_content_type $csp { - default ""; - "~^text/html" "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"; - } - - server { - # 404 for any request that does match the server names defined below - listen 80; - return 404; - } - - server { - listen 80; - autoindex on; - root /www/data; - expires $expires; - server_name www.offen.dev staging.offen.dev; - add_header Content-Security-Policy $csp; - add_header Strict-Transport-Security 'max-age=604800; includeSubDomains'; - add_header Referrer-Policy 'origin-when-cross-origin'; - add_header X-Content-Type-Options 'nosniff'; - add_header X-XSS-Protection '1; mode=block'; - - location /api/ { - proxy_pass http://server; - proxy_redirect off; - } - - location /vault/ { - proxy_pass http://server; - proxy_redirect off; - } - - location /auditorium/ { - proxy_pass http://server; - proxy_redirect off; - } - - location /script.js { - proxy_pass http://server; - proxy_redirect off; - } - - location /healthz { - proxy_pass http://server; - proxy_redirect off; - } - - location /versionz { - proxy_pass http://server; - proxy_redirect off; - } - - location /normalize.css { - proxy_pass http://server; - proxy_redirect off; - } - - location /skeleton.css { - proxy_pass http://server; - proxy_redirect off; - } - - location /favicon.ico { - root /www/data/theme/images; - } - - error_page 404 /404.html; - location = /404.html { - internal; - root /www/data; - add_header X-Robots-Tag "noindex, nofollow, nosnippet, noarchive" always; - } - } -} - diff --git a/docker-compose.yml b/docker-compose.yml index 69c1620..6f0c918 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,22 +9,6 @@ services: - 8000:80 depends_on: - homepage - - server - - server: - image: offen/offen@sha256:91845f3e0e80f7d1871f58dabd08e8614ec70f6ff37ef7e9b675d0f4f1c9ca13 - command: serve - volumes: - - ./bootstrap.yml:/bootstrap.yml - - database:/data - environment: - OFFEN_APP_EVENTRETENTIONPERIOD: 4464h - OFFEN_APP_DISABLESECURECOOKIE: '1' - OFFEN_DATABASE_CONNECTIONSTRING: /data/offen.db - OFFEN_SERVER_PORT: 8080 - OFFEN_SERVER_REVERSEPROXY: '1' - OFFEN_SECRETS_COOKIEEXCHANGE: 8jeKYbbnywoYIZznu4HffQ== - OFFEN_SECRETS_EMAILSALT: eypctS7SVKM1Ureb61db5Q== homepage: build: @@ -40,4 +24,3 @@ services: volumes: homepagedeps: - database: diff --git a/homepage/theme/templates/base.html b/homepage/theme/templates/base.html index 69510a0..a78e818 100644 --- a/homepage/theme/templates/base.html +++ b/homepage/theme/templates/base.html @@ -25,8 +25,8 @@ {% assets filters="postcss,cssmin", output="css/style.min.css", "css/tachyons.min.css", "css/fix.css", "css/fonts.css" %} {% endassets %} - - + + {% if OFFEN_ACCOUNT_ID and not no_stats %} {% endif %} diff --git a/nginx.conf b/nginx.conf index c8f0b3f..727f45f 100644 --- a/nginx.conf +++ b/nginx.conf @@ -7,10 +7,6 @@ http { server homepage:8000; } - upstream server { - server server:8080; - } - map $request_uri $expires { default off; "~-[0-9a-z]{10}\.js$" 1d; @@ -31,50 +27,6 @@ http { add_header X-Content-Type-Options 'nosniff'; add_header X-XSS-Protection '1; mode=block'; - location /api/ { - proxy_pass http://server; - proxy_redirect off; - } - - location /vault/ { - proxy_pass http://server; - proxy_redirect off; - } - - location /auditorium/ { - proxy_pass http://server; - proxy_redirect off; - } - - location /script.js { - proxy_pass http://server; - proxy_redirect off; - } - - location /normalize.css { - proxy_pass http://server; - proxy_redirect off; - } - - location /skeleton.css { - proxy_pass http://server; - proxy_redirect off; - } - - location /healthz { - proxy_pass http://server; - proxy_redirect off; - } - - location /versionz { - proxy_pass http://server; - proxy_redirect off; - } - - location /favicon.ico { - root /www/data/theme/images; - } - location / { proxy_pass http://homepage; proxy_redirect off;