Blog



su - $USERID -c "$COMMAND1; $COMMAND2; ... "

# EX
sudo su - hamonikr -c "echo \"HamoniKR 1.4 Update\" /home/hamonikr/Desktop/message.txt; firefox;"



bash 대소문자 변환


x="HELlo"
y=${x,,}
z=${x^^}

echo "x : $x"
echo "y : $y"
echo "z : $z"


# output
x : HELlo
y : hello
z : HELLO



사내 사이트에 적용된 SSL 인증서가 자동 갱신 되지 않는 문제 발생 하였습니다.

Letsencrypt 갱신 혹은 자동화 스크립트 문제라 생각되어 확인 하니 두가지 다 문제가 있었습니다.


자동화 스크립트의 경우 경로의 문제라 어렵지 않게 수정하였으나,

Letsencrypt의 경우 자동 인증을 위해 사용해야 하는 경로 및 포트가 있는데 기존 Apache 설정은 해당 경로마저 포트 포워딩하여 80, 443 포트를 사용할 수 없어 문제가 되었습니다.


이를 해결하기 위해 해당 경로로 접속하는 경우 포트포워딩 하지 않고 그 이외의 접속만 포워딩 하도록 변경할 필요가 있었습니다.


이를 위해 mod_rewrite 을 사용하기로 하였습니다. 

해당 문서는 mod_rewrite 에서 특정 uri 을 제외하고 리다이렉션을 적용하는 방법을 설명합니다.


  • 예외처리가 필요한 url : pms.invesume.com/.well-known/acme-challenge/*


# 포워딩 적용 대상
RewriteCond %{SERVER_NAME} =pms.invesume.com

# 예외 설정
# RewriteCond %{REQUEST_URI} ^/예외적용할uri/.*$
RewriteCond %{REQUEST_URI} ^/.well-known/acme-challenge/.*$

# 포워딩할 uri
RewriteRule ^ https://pms.invesume.com:444%{REQUEST_URI} [END,NE,R=permanent]



# 윈도우 cmd 창에서 실행

MD5
CertUtil -hashfile [filepath/name] MD5

SHA256
CertUtil -hashfile [filepath/name] SHA256



XE 서버 이전


※ 해당 문서는 ubuntu 18.04 서버를 기준으로 작성되었습니다.

※ DB 이전은 전체 DB를 이전하는 방식으로 적용하였습니다. 사용 중인 DB에 이전하는 경우 해당 DB만 이전하시기 바랍니다.



이전 준비

디렉토리 백업

tar -cvf xe_site.tar.gz $xe_site_path



DB 백업

mysqldump -u root -p –all-databases > all_db.sql


해당 두 파일 (xe_site.tar.gz, all_db.sql) 을 이전할 서버로 옮긴다





사전 설치

필수 패키지 설치

# php 설치 - v7.0
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.0 -y

sudo apt install php7.0-xml
sudo apt install php7.0-gd
sudo apt install php7.0-mysql

# files 폴더가 없는 경우 생성
mkdir files

# files 폴더 권한 변경
chmod 707 ./files


# mysql 설치 - v5.7
sudo apt-get install mysql-client-5.7
sudo apt-get install mysql-server-5.7


디렉토리 이전

mv xe_site.tar.gz $(설치할 경로)
cd $(설치할 경로)
tar -xvf xe_site.tar.gz

cd $(압축해제한폴더)
chmod 707 -R files



DB 이전

mysql -u root -p < all_db.sql



Apach2 설정

cd /etc/apache2/sites-available

# 설정파일 생성
vi $(설정파일명).conf


# 설정파일 내용
<VirtualHost *:80>
        ServerName $(url)
        ServerAdmin ****@****.com

        DocumentRoot $(xe path)

        ErrorLog ${APACHE_LOG_DIR}/log_file_name-error.log
        CustomLog ${APACHE_LOG_DIR}/log_file_name-access.log combined

        <Directory "$(xe path)">
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Require all granted
        </Directory>
</VirtualHost>


# 저장후 아래 명령 입력
sudo a2ensite $(설정파일명)
a2enmod rewrite

sudo service apache2 restart



확인

  • 브라우저에 도메인 입력 후 접속하여 확인





기타 오류 발생 시

DB 접속 오류가 발생했습니다. DB 정보를 입력해 주세요.

# DB 설정 변경
vi $(XE설치경로)/files/config/db.config.php

<?php if(!defined("__XE__")) exit();
$db_info = (object)array (
  'master_db' =>
  array (
    'db_type' => 'mysqli',
    'db_port' => '3306',
    'db_hostname' => 'localhost',     <---- 127.0.0.1 인 경우 localhost 로 변경한다.
    'db_userid' => 'root',
    'db_password' => '.....',
    'db_database' => '......',
    'db_table_prefix' => 'xe_',
  ),
  'slave_db' =>
  array (
    0 =>
    array (
      'db_type' => 'mysqli',
      'db_port' => '3306',






※ 해당 문서는 node js 에 대한 이해가 필요하며 node js에 대해선 다루지 않습니다.



certbot 설치

sudo add-apt-repository ppa:certbot/certbot

sudo apt-get update

sudo apt-get install certbot





certbot 으로 SSL 인증서 생성을 위한 사이트 검증

sudo certbot certonly --manual

# output
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): 
# 프로토콜 부분 없이 도메인 이름을 입력
# ex : yourdomain.com


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
One or more of the entered domain names was not valid:

1: Requested name 1 is an IP address. The Let's Encrypt certificate authority
will not issue certificates for a bare IP address.

Would you like to re-enter the names?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: 
# Y


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:

m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E.1knlOBvZlzNYvhOwCYA_Zb1Oe4PyM5Xx6idZy92QVSQ

And make it available on your web server at this URL:

http://test.site/.well-known/acme-challenge/m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue


# 입력하지 않고 대기


위의 상태까지 진행하면 인증서를 발급 받기 전 유효한 사용자의 요청인지 확인하기 위한 준비가 끝났습니다.


다른 창으로 접속하여 인증서를 발급 받기 위한 준비를 진행합니다.


준비가 완료되면 위의 창으로 돌아와 엔터를 입력합니다.





사이트 인증 및 인증서 생성

인증서를 적용할 node js 디렉토리로 이동합니다.

해당 node js 에서 접근 가능한 경로에 폴더 및 파일을 생성합니다.

접근가능한 url 및 파일 내용은 다음과 같습니니다.

  • URL : http://test.site/.well-known/acme-challenge/m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E
  • 파일내용 : m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E.1knlOBvZlzNYvhOwCYA_Zb1Oe4PyM5Xx6idZy92QVSQ


URL 과 내용은 위에서 출력 되었던 내용입니다.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:

m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E.1knlOBvZlzNYvhOwCYA_Zb1Oe4PyM5Xx6idZy92QVSQ

And make it available on your web server at this URL:

http://test.site/.well-known/acme-challenge/m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


# 해당 작업이 완료되면 다음과 같은 구조를 가질 것 입니다.
service
├─ .well-known
│      └─ acme-challenge
│              └─ m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E
└─ service.js


완료되었다면 정상적인지 확인하기 위해 브라우저를 열고 URL 을 입력해 접속합니다.

  • URL : http://test.site/.well-known/acme-challenge/m7_68WkPyhNEZ6cCGF-5ywMJ3auDiy6N64-c667ph3E


브라우저가 파일을 다운로드 하며 해당 파일의 내용이 동일하다면 준비가 완료된 것 입니다.

만약 위와 같이 진행되지 않는 경우 처음부터 다시 시작해야 합니다.


모든 것이 정상이라면 위로 돌아가서 엔터를 입력합니다.

이상 없이 진행되었다면 완료되었다는 메시지와 함께 내용이 나올 것 입니다.





node js 에 인증서 적용하기

사이트에 인증서를 적용하도록 합니다.

다음의 코드를 server.js 에 반영합니다.

// Dependencies
const fs = require('fs');
const http = require('http');
const https = require('https');
const express = require('express');

const app = express();

// Certificate
const privateKey = fs.readFileSync('/etc/letsencrypt/archive/yourdomain.com/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/archive/yourdomain.com/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/archive/yourdomain.com/chain.pem', 'utf8');

const credentials = {
	key: privateKey,
	cert: certificate,
	ca: ca
};

app.use((req, res) => {
	res.send('Hello there !');
});

// Starting both http & https servers
const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);

httpServer.listen(80, () => {
	console.log('HTTP Server running on port 80');
});

httpsServer.listen(443, () => {
	console.log('HTTPS Server running on port 443');
});


적용이 완료되면 서버를 구동(혹은 재시작)한 뒤 브라우저로 접속해 SSL 인증서 적용을 확인합니다.


※ 인증서 적용이 되지 않는다면 해당 인증서 및 인증서 디렉토리 권한을 확인해 보시기 바랍니다.

※ 간혹 적용이 되었으나 브라우저에서 갱신이 느린 경우가 있습니다. 이상이 없는데 적용이 안되는 경우 다른 브라우저로 접속해서 확인해 보시기 바랍니다.






※ 해당 코드는 열려있는 모든 터미널 창이 닫힙니다 사용에 주의해 주시기 바랍니다


#!/bin/bash
PPPID=$(awk '{print $4}' "/proc/$PPID/stat")
kill $PPPID

PPID : 상위 프로세스 ID 이며 이 경우 쉘(script) 입니다

PPPID : PPID의 상위 프로세스 ID 이며 이 경우 터미널 창입니다

리눅스 bash 숫자 비교


# 1 == 1 ? YES
if [ 1 = 1 ]; then echo YES; else echo NO; fi
YES

# 1 >=1 ? YES
if [ 1 -ge 1 ]; then echo YES; else echo NO; fi
YES

# 1 > 1 ? NO
if [ 1 -gt 1 ]; then echo YES; else echo NO; fi
NO

# 1 <= 1 ? YES
if [ 1 -le 1 ]; then echo YES; else echo NO; fi
YES

# 1 < 1 ? NO
if [ 1 -lt 1 ]; then echo YES; else echo NO; fi
NO



요청사항

  • 접속자의 로그인/아웃 시간 정보를 남길 것
  • 시간 타입은 time(NULL) 값의 int 값



time(NULL) 이란?

  • C 언어 에서 1970년 1월 1일 00:00:00 UTC 이후 몇 초가 흐른 시점인지 출력해 주는 명령어



ubuntu 에서 time(NULL) 출력하기

date "+%s"

날짜 계산하기

# 1970년 1월 1일 자정을 기준으로 초단위로 환산
first_date=`date -d "20180101" "+%s"`
second_date=`date -d "20190815" "+%s"`

# 두 날짜의 차이 계산(단위:일)
diff_date=`echo "($second_date - $first_date) / 86400" | bc`
echo $diff_date

# 두 날짜의 차이 계산(단위:시간)
diff_hour=`echo "($second_date - $first_date) / 3600" | bc`
echo $diff_hour


하모니카 백업/복구 기능을 테스트 하던 중 문제가 되는 사례 발생

  • 백업할 대상 : /
  • 백업 데이터 저장 경로 : /backup


위와 같은 경우 재귀적 호출이 일어나 계속해서 백업을 시도하는 사례가 발생

해당 폴더를 제외해야 했다



GUI 로 설정하기

설정 > 필터 에서 제외하거나 포함할 패턴을 지정하여 적용하면 제외 혹은 포함이 가능하다





터미널에서 설정

/etc/timeshift.json
# 제외폴더 : /backup
# 포함폴더 : /added

{
  "backup_device_uuid" : "d289f358-7cab-471d-93bc-dc6903aaa04c",
  "parent_device_uuid" : "",
  "do_first_run" : "false",
  "btrfs_mode" : "false",
  "include_btrfs_home_for_backup" : "false",
  "include_btrfs_home_for_restore" : "false",
  "stop_cron_emails" : "true",
  "btrfs_use_qgroup" : "true",
  "schedule_monthly" : "false",
  "schedule_weekly" : "false",
  "schedule_daily" : "true",
  "schedule_hourly" : "false",
  "schedule_boot" : "false",
  "count_monthly" : "2",
  "count_weekly" : "3",
  "count_daily" : "5",
  "count_hourly" : "6",
  "count_boot" : "5",
  "snapshot_size" : "20150528070",
  "snapshot_count" : "551975",
  "exclude" : [
    "/root/**",
    "/home/hamonikr/**",

    "/backup/**",
    "+ /added/**"

  ],
  "exclude-apps" : [
  ]
}



deb 패키지 추출하기



ar 로 압축해제하기

# ar x 패키지파일
ar x packge.deb


# 자세한 출력이 필요한 경우
ar -xv pacage.deb

# out print
x - debian-binary
x - control.tar.xz
x - data.tar.xz





dpkg 로 추출하기

데비안 기반 배포판을 사용하거나 dpkg를 사용하는 경우 deb 패키지를 시스템에 설치하지 않고 dpkg를 사용하여 deb 패키지를 추출할 수도 있습니다.

# dpkg -x 패키지파일 해제할경로
dpkg -x package.deb /drectory/path





.gz 압축하기/압축풀기


gz 압축풀기

# -d 는 decompress
gzip -d filename.gz



gz 압축하기

# abc.jpg 를 gz 로 압축하는 경우의 예시입니다.
# 실행하면 abc.jpg는 사라지고 압축된 abc.gz 파일이 생성됩니다.
gzip abc.jpg

# gz는 여러개의 파일을 하나로 압축하는 용도가 아닙니다.
# 여러개의 파일을 압축 하시려면 7z, zip, tar 압축 또는 묶기를 사용하시기를 바랍니다.



help

Compress or uncompress FILEs (by default, compress FILES in-place).

Mandatory arguments to long options are mandatory for short options too.

  -c, --stdout      write on standard output, keep original files unchanged
  -d, --decompress  decompress
  -f, --force       force overwrite of output file and compress links
  -h, --help        give this help
  -k, --keep        keep (don't delete) input files
  -l, --list        list compressed file contents
  -L, --license     display software license
  -n, --no-name     do not save or restore the original name and time stamp
  -N, --name        save or restore the original name and time stamp
  -q, --quiet       suppress all warnings
  -r, --recursive   operate recursively on directories
  -S, --suffix=SUF  use suffix SUF on compressed files
  -t, --test        test compressed file integrity
  -v, --verbose     verbose mode
  -V, --version     display version number
  -1, --fast        compress faster
  -9, --best        compress better
  --rsyncable       Make rsync-friendly archive

With no FILE, or when FILE is -, read standard input.

Report bugs to <bug-gzip@gnu.org>.



우분투 서버 시간 변경



# /usr/share/zoneinfo/ 에서 대륙과 대륙에 해당하는 국가 정보 확인 가능
# 변경
sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# 확인
date -R

게스트 시작 알림창 사용하지 않도록 설정

# /etc/guest-session/prefs.sh 파일 생성 혹은 수정

touch $HOME/.skip-guest-warning-dialog



게스트 시작 알림창 발생 시간 설정

# /etc/guest-session/prefs.sh 파일 생성 혹은 수정

echo "export DIALOG_SLEEP = 8">> $ HOME / .profile



참고 : https://help.ubuntu.com/community/CustomizeGuestSession#Startup_dialog


개요

  • 추진배경 : 업무 진행 중 윈도우 서버를 사용해야 하는 상황이 빈번하게 발생

현황 및 문제점

  • 현황 : 사용중인 PC는 하모니카 데스크탑 이고 서버는 윈도우 서버이며 양쪽 모두 컨트롤해야 하는 상황
  • 문제점 : 두 PC를 한 곳에서 컨트롤 할 수 없어 이동이 빈번하게 발생

방안

  • 원격 접속이 가능한 패키지 활용하여 원격에서 컨트롤 할 수 있도록 구성
# 패키지 최신버전으로 업데이트
sudo apt-get update

# 패키지 설치
sudo apt install xrdp xorgxrdp
sudo apt install -y freerdp-x11

echo env -u SESSION_MANAGER -u DBUS_SESSION_BUS_ADDRESS xfce4-session>~/.xsession

sudo reboot


# 접속
sudo xfreerdp /v:192.168.0.0 /u:administrator /p:password +clipboard /size:1240x820